Prolog - sort sublists of a list - prolog

I want to sort the sublists of a list which contains integers eliminating the duplicates. Example:
[1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7]
=>>>
[1, 2, [1, 4], 3, 6, [1, 3, 7, 9, 10], 5, [1], 7].
I know that i have to work with functor s(but i didn't really get it).
Here is my code : (the (insert+sorting) function works in a simple list of integers,but don't work here. i'm getting red false everytime)
insert(E,[],[E]).
insert(E,[H|T],[H|L]):-
E>H,
insert(E,T,L).
insert(E,[H|T],[H|T]):-
E=H,
!.
insert(E,[H|T],[E|[H|T]]):-
E<H,
!.
sort([],[]).
sort([i(H)|T],L):-
sort(T,L1),
insert(i(H),L1,L).

You could try a solution like this, it uses the the sort/2 predicate to sort sublists:
sort_sublists([], []).
sort_sublists([X|Xs], List) :-
(integer(X) ->
List = [X | List1]
;
sort(X, Sorted),
List = [Sorted | List1]
),
sort_sublists(Xs, List1).
Example call:
?- set_prolog_flag(answer_write_options,[max_depth(0)]).
true.
?- sort_sublists([1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7], X).
X = [1,2,[1,4],3,6,[1,3,7,9,10],5,[1],7].

#Eduard Adrian it's hard to answer in comments, so first thing you need to do is to remove duplicates from the nested lists.
Here i tried that and you can see different cases that you need to handle. One example:(Head of your list can be a list but it's tail will be empty this happends if last element of your list is a list) in that case you need to define another predicate which will match your recursive call.
Once you have removed duplicates you can use simple sorting algorithm but you have to check if the head is a list then you sort innner list first and place it to the same place otherwise call sort predicate.
As you asked how check if an element is_list or integer, for that you can always use built-in because those predicates you can't write by yourself.

Related

Prolog doesn't return a value

I have the following code:
pair_list([X,Y],[[X,Y]]).
pair_list([E,Z|X],[K|Y]):- [E,Z]==K, pair_list(X,Y).
When I run it, it gives correct output for
?- pair_list([1, 2, 3, 4, 5, 6], [[1, 2], [3, 4], [5, 6]]).
true ;
but when I run
?- pair_list([1,2, 3, 4, 5, 6], X).
I just get false.
My question is why don't I get X=[[1, 2], [3, 4], [5, 6]]
You are almost there: all you need to do is moving [E,Z] into the head, eliminating K:
pair_list([X,Y],[[X,Y]]).
pair_list([E,Z|X],[[E,Z]|Y]) :- pair_list(X,Y).
Demo 1.
Note that the base clause can be replaced with one based on empty lists:
pair_list([], []).
pair_list([E,Z|X],[[E,Z]|Y]) :- pair_list(X,Y).
Demo 2.
Also note that your program is not going to work with a list that has an odd number of items. In order to fix this, add a separate base clause that handles a list with a single item either by dropping the item, making a pair with some fixed atom, or doing something else that you find useful in this case.

Adding two lists representing numbers in prolog

The task says: the numbers are represented by lists (e.g. 123 = [1, 2, 3]), write a predicate which adds two such numbers. (e.g. sum([4, 5, 6], [9], [4, 6, 5])).
I have been thinking how to express this recursively but what trips me up is when the sizes of the arrays vary. It seems, that this would be simple if the arrays were reverted, so that HEAD is actually the last element. Because the problem for me is that my sum looks like that that:
[4, 5, 6]
+
[9]
instead of
[4, 5, 6]
+
[9]
What could be the proper way to write such predicate? I need some pointers or reference for help...
Here is my implementation:
sum(L1,L2,OutL):-
reverse(L1,List1),reverse(L2,List2),
add_lists(List1,List2,0,List3),
reverse(List3,OutL).
add_lists([],[],0,[]).
add_lists([],[],1,[1]).
add_lists([],[H|T],C,[H1|T]):-H1 is H+C.
add_lists([H|T],[],C,[H1|T]):-H1 is H+C.
add_lists([H|T],[H1|T1],C,[H2|T2]):-NH is H1+H,
(NH > 10 -> NC is 1,H2 is NH+C-10; H2 is NH+C,NC is 0),
add_lists(T,T1,NC,T2).
The idea is to reverse lists in order to add right positions and avoid the problem you referred. Also you just keep a carry which is 1 if an addition is greater than 10 where you reduce 10.
Example:
?- sum([4, 5, 6], [9], L).
L = [4, 6, 5] ;
false.

How to permute in Prolog the elements of a list composed of sub-list and atoms

Let us consider lists such as L=[[7,3,4],9,[4,5],[1,3,5],4] where components could be lists or atoms. How to produce this type of permutation results:
R = [[7, 3, 4], 9, [4, 5], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [5, 4], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [4, 5], [1, 5, 3], 4]
....
In fact, we would like to have all the possible permutations of the sub-lists of L while the atom should remain unchanged.
I wrote a classical predicate permutation(OriginalList,PermutedList), and an allperm predicate that apply the maplist function to this permutation predicate:
permutation([],[]).
permutation(L,[T|Q]) :-
select(T,L,L1),
permutation(L1,Q).
/*L is the list to permute, R the result*/
allperm(L,R) :-
maplist(permutation,L,R).
It functions only in the special case where L is composed of lists and doesn't function when L is heterogeneous (atoms and lists).
Could you provide hints or elements of solution to do the right permutation?
The following modification should do:
permutation(X,X).
permutation(L,[T|Q]) :-
dif(L,[T|Q]),
select(T,L,L1),
permutation(L1,Q).
allperm(L,R) :-
maplist(permutation,L,R).
We extend the “identity” permutation to any Prolog term (first clause of permutation) and disallow it in the second clause (which can only be applied to lists anyway).

Removing list within lists based on nth element

I've got a list of lists, for example:
[[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]]
I'd like to get the last element of and check to see if is the same as the 4th element of any of the other lists. If it is the same then leave the list alone, but if it is unique then remove the list. So in the example above I would be left with:
[[3, 4, 7, 12], [2, 6, 8, 12]]
Essentially I want to be remove all the lists where the last element is unique.
I've written a predicate to get the nth element:
my_membership(X, [X|_]).
my_membership(X, [_|Tail]) :-
my_membership(X, Tail).
where:
my_membership([_,_,_,Fourth],[[3, 4, 7, 12], [2, 6, 8, 12]]).
gives:
Fourth = 12
Fourth = 12
Start by building two basic predicates:
last([X], X).
last([_|T], X) :- last(T, X).
forth([_,_,_,F|_], F).
The first predicate extracts the last element of a list; the second predicate extracts the forth element of a list.
Now you can make a predicate that counts how many tomes an element X appears in forth place in any of the lists of a list of lists. Below, H in [H|T] is a list:
matching_forth([], _, 0).
matching_forth([H|T], X, R) :- forth(H, X), matching_forth(T, X, RR), R is RR + 1.
matching_forth([_|T], X, R) :- matching_forth(T, X, R).
With these predicates in place you can build a predicate for checking your condition. It will have three clauses - for a situation when the list is empty, for when the head list has a matching forth element in another list, and for situations when it doesn't:
my_membership([], [], _).
my_membership([H|T], [H|R], A) :-
last(H, X), matching_forth(A, X, C), C > 1, my_membership(T, R, A).
my_membership([_|T], R, A) :- my_membership(T, R, A).
The first and last clauses are self-explanatory. The middle clause extracts the last element from the head list, counts how many times it matches the forth element in the original list of lists (A stands for "all"), and adds H to the result when there is a match. Adding happens through unification with the head of the result list.
Finally, you need a my_membership/2 predicate to start off the recursive chain that passes along the original list of lists:
my_membership(L, R) :- my_membership(L, R, L).
Demo.
Here's a different twist on a potential solution. It uses an accumulator to collect members that we've seen already and checks along the way. The result saves those that have either been seen or are currently in the tail. It requires the use of the built-in, memberchk/2.
my_membership(L, R) :-
my_membership(L, [], R).
my_membership([], _, []).
my_membership([X|T], Acc, R) :-
X = [_,_,_,D],
( memberchk([_,_,_,D], Acc)
-> R = [X|T1],
Acc1 = Acc
; memberchk([_,_,_,D], T)
-> R = [X|T1],
Acc1 = [X|Acc]
; R = T1,
Acc1 = Acc
),
my_membership(T, Acc1, T1).
| ?- my_membership([[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]], L).
L = [[2,3,5,6],[1,6,7,6],[3,4,7,12],[2,6,8,12]]
yes

Combinatios in List of LIsts Prolog

I need to find the combinations in a list of lists.
For example give the following list,
List = [[1, 2], [1, 2, 3]]
These should be the output,
Comb = [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3]]
Another example:
List = [[1,2],[1,2],[1,2,3]]
Comb = [[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3]....etc]
I know how to do it for a list with two sublists but it needs to work for any number of sublists.
I'm new to prolog, please help.
try([],[]).
try([L|Ls],[M|Ms]):-
member(M,L),
try(Ls,Ms).
all(L,All) :- findall(M, try(L,M), All).
try returns one list composed of elements of the sublists of the first argument. all finds all such lists.
Here is your answer, cut and dry, as a fellow new prolog programmer myself.
%elementInList(input list, output answer)
answer(ListOfList, AnswerInList) :-
findall(Ans, combList(ListOfList, Ans), AnswerInList).
%combList(ListOfList, Comb) :-
combList([], []).
combList([Head|Tail], Comb) :-
combList(Tail, [Element|Tempcomb]),
elementInList(Head, Element).
%elementInList(List, Element)
elementInList([Head|_], Head).
elementInList([Head|Tail], Element) :-
elementInList(Tail, Element).
Using the definition answer(InputList, OutputResult), where e.g.
answer([[1,2],[7,8]],Comb).
Comb = [[1, 7], [2, 7], [1, 8], [2, 8]].
and e.g.
answer([[1,2],[2,8],[3,6,9]],Comb).
Comb = [[1, 2, 3], [2, 2, 3], [1, 8, 3], [2, 8, 3], [1, 2, 6], [2, 2, 6], [1, 8|...], [2|...], [...|...]|...].
and so on [X,Y,Z,..] for any number of sublists. You're welcome.

Resources