Flatten list of lists of lists into single list - prolog

Trying to flatten list of lists of lists into single list with following modification. The lowest level list should merge into one item of resultant list and dash should be added between them. More you can see from following:
Input:
L = [[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]]
Expected output:
Res = [A-B,C-D,E-F,G-H]
Here is my code:
toList([],_).
toList([H|T],Out) :-
toList1(H,Out1),
newOut2 = [Out|Out1],
toList(T,newOut2).
toList1([],newOut1).
toList1([[A],[B]],Out1) :-
newOut1 = [A-B],
toList1([],newOut1).
Should work like toList([[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]], Res).

You can actually describe this relation with a single predicate, let's call it lists_pairs/2. There are two cases to cover:
If the list of lists is empty then the list of pairs is empty as well.
If the head of the first list is of the form [[A],[B]] then the head of the second list is A-B and the relation has to hold for the tails of the lists as well.
You can express this in Prolog like so:
lists_pairs([],[]). % case 1
lists_pairs([[[A],[B]]|Ls],[A-B|Ps]) :- % case 2
lists_pairs(Ls,Ps).
Your example query yields the desired answer:
?- lists_pairs([[[A],[B]],[[C],[D]],[[E],[F]],[[G],[H]]], Res).
Res = [A-B, C-D, E-F, G-H].
You can also use this predicate in the other direction:
?- lists_pairs(L, [A-B, C-D, E-F]).
L = [[[A], [B]], [[C], [D]], [[E], [F]]].
And the most general query works as well:
?- lists_pairs(L, P).
L = P, P = [] ;
L = [[[_G22], [_G28]]],
P = [_G22-_G28] ;
L = [[[_G22], [_G28]], [[_G43], [_G49]]],
P = [_G22-_G28, _G43-_G49] ;
L = [[[_G22], [_G28]], [[_G43], [_G49]], [[_G64], [_G70]]],
P = [_G22-_G28, _G43-_G49, _G64-_G70] ;
.
.
.

Related

Append a Star after every element of a given list in prolog

In this predicate listStar(L,R), I want to append a * after every element of a given list e.g.:
?- listStar([1,2,3,4] , R).
R = [1,*,2,*,3,*,4,*]
listStar([],[]).
listStar([X|Xs],[X,Z|Zs]) :- Z is ['*'],listStar(Xs,Zs).
After the execution of this code i got this result:
R = [1, 42, 2, 42, 3, 42, 4, 42].
Any help !
elems_star([], []).
elems_star([H|T], [H, '*'|S]) :-
elems_star(T, S).
Result:
?- elems_star([1, 2, 3, 4], L).
L = [1,*,2,*,3,*,4,*].
Whenever you are using Prolog to describe lists it's worthwhile to consider using DCGs for the task, since they yield easily readable code:
starified([]) --> % if the argument list is empty
[]. % so is the starified list
starified([X|Xs]) --> % if the argument list starts with an X followed by some tail Xs
[X,*], % the starified list contains an X followed by a star
starified(Xs). % and the tail is starified as well
list_starified(L,S) :-
phrase(starified(L),S). % using phrase/2 to call the DCG starified//1
The predicate list_starified/2 can then be the used to describe a list with added stars:
?- list_starified([1,2,3,4],S). % What's the corresponding starified list to [1,2,3,4]?
S = [1,*,2,*,3,*,4,*]
Or to remove the stars from a starified list:
?- list_starified(L,[1,*,2,*,3,*,4,*]). % What's the corresponding non-starified list to [1,*,2,*,3,*,4,*]?
L = [1,2,3,4] ? ;
no
Or to check if the second list is starified as described above, by writing a _ instead of a variable-name for the first argument:
?- list_starified(_,[1,*,2,*,3,*,4,*]). % Is [1,*,2,*,3,*,4,*] a proper starified list?
yes
?- list_starified(_,[1,*,2,*,3,*,4]). % Is [1,*,2,*,3,*,4] a proper starified list?
no
Or it can be used to generate pairs of lists and their corresponding counterparts with added stars:
?- list_starified(L,S). % what lists and corresponding starified list are there?
L = S = [] ? ; % the empty list
L = [_A], % the one-element list
S = [_A,*] ? ;
L = [_A,_B], % the two-element list
S = [_A,*,_B,*] ? ;
L = [_A,_B,_C], % the three-element list
S = [_A,*,_B,*,_C,*] ?;
.
.
.

Same elements in lists

I'm trying to write a predicate that determines whether the first list have the same elements with either two other lists in Prolog. This is what I have tried:
same([],[],[]).
same([A|As],[B|Bs],[C|Cs]) :- A = B, A = C, common(As,Bs,Cs).
The output is supposed to be something like this:
?- same(E,[1,6,8,2,3],[3,7,9,10,2]).
E = [] ;
E = [2] ;
E = [2, 3] ;
E = [3] ;
false.
I have no idea where I went wrong here. Any help would be much appreciated!
Your procedure will succeed only when the three lists have the same length and every item from the first list unifies with the other corresponding items in the remaining lists. That is, if lists are ground it will only succeed if the three lists are the same.
You may try something like this:
same([], _, _).
same([A|As], Bs, Cs):-
append(_, [A|Bs1], Bs),
select(A, Cs, Cs1),
same(As, Bs1, Cs1).
where the recursive step "takes" an item from the second list and selects it from the the third one.
sample run:
?- same(E,[1,6,8,2,3],[3,7,9,10,2]).
E = [] ;
E = [2] ;
E = [2, 3] ;
E = [3] ;
false.

Filter list in prolog

I'm trying to rewrite code from Haskell to Prolog.
count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)
f :: [Integer] -> [Integer]
f [] = []
f list = filter (\x -> count x list == 1) list
This code return list that contains elements that appears only once in the list.
So if I have list [1,1,2,2,3,4,4,5] this function returns [3,5]
I tried to find filter construction in Prolog but seems there no such thing. How can I make similar function in Prolog ?
To the existing answers, I would like to add an answer that is quite general in the sense that you can use it in multiple directions.
Building block: list_element_number/3
I start with the following predicate, defining a relation between:
a list Ls0
an element E
the number N of occurrences of E in Ls0
Here it is:
list_element_number(Ls0, E, N) :-
tfilter(=(E), Ls0, Ls),
length(Ls, N).
This solution uses tfilter/3 from library(reif). The predicate subsumes the function count you have posted. The main benefit of this predicate over the function is that the predicate can be used not only in those cases that even Haskell can do easily, such as:
?- list_element_number([a,b,c], a, N).
N = 1.
No, we can use it also in other directions, such as:
?- list_element_number([a,b,c], X, 1).
X = a ;
X = b ;
X = c ;
false.
Or even:
?- list_element_number([a,b,E], X, 2).
E = X, X = a ;
E = X, X = b ;
false.
Or even:
?- list_element_number([A,B,C], X, 3).
A = B, B = C, C = X ;
false.
And even in the most general case, in which all arguments are fresh variables:
?- list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [E, E],
N = 2 ;
Ls = [E, E, E],
N = 3 .
We can fairly enumerate all answers like this:
?- length(Ls, _), list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [_160],
N = 0,
dif(E, _160) ;
Ls = [E, E],
N = 2 .
Main predicate: list_singletons/2
Using this building block, we can define list_singletons/2 as follows:
list_singletons(Ls, Singles) :-
tfilter(count_one(Ls), Ls, Singles).
count_one(Ls, E, T) :-
list_element_number(Ls, E, Num),
cond_t(Num=1, true, T).
This uses cond_t/3 and (again) tfilter/3 from library(reif).
Sample queries
Here are a few sample queries. First, the test case you have posted:
?- list_singletons([1,1,2,2,3,4,4,5], Singles).
Singles = [3, 5].
It works as desired.
Now a case involving variables:
?- list_singletons([A,B], Singles).
A = B,
Singles = [] ;
Singles = [A, B],
dif(A, B).
On backtracking, all possibilities are generated: Either A = B holds, and in that case, there is no element that occurs only once. Or A is different from B, and in that case both A and B occur exactly once.
As a special case of the above query, we can post:
?- list_singletons([A,A], Singles).
Singles = [].
And as a generalization, we can post:
?- length(Ls, _), list_singletons(Ls, Singles).
Ls = Singles, Singles = [] ;
Ls = Singles, Singles = [_7216] ;
Ls = [_7216, _7216],
Singles = [] ;
Ls = Singles, Singles = [_7828, _7834],
dif(_7828, _7834) ;
Ls = [_7216, _7216, _7216],
Singles = [] ;
Ls = [_7910, _7910, _7922],
Singles = [_7922],
dif(_7910, _7922) .
Enjoy the generality of this relation, obtained via logical-purity.
A more simple version :
filter_list(L,OutList):-findall(X, (select(X,L, L1),\+member(X, L1)) , OutList).
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
Without findall, you can try
filter_list(In, Out) :- filter_list(In, _, Out).
filter_list([], [], []).
filter_list([H|T], L1, L2) :-
filter_list(T, LL1, LL2),
( member(H, LL1)
-> L1 = LL1, L2 = LL2
; (select(H, LL2, L2)
-> L1 = [H|LL1]
; L1 = LL1, L2 = [H|LL2])).
without counting...
filter_uniques([],[]).
filter_uniques([H|T],F) :-
delete(T,H,D),
( D=T -> F=[H|R],S=T ; F=R,S=D ),
filter_uniques(S,R).
a more direct rewrite of your code, with library(yall) support for inlining of the filter predicate (the first argument to include/3)
filt_uniq(L,F) :-
include({L}/[E]>>aggregate(count,member(E,L),1),L,F).
A simple version:
(see the comment by #false below, the version with findall/3 has some inconsistency problems in more complex queries but second version looks ok however it is definitely not so efficient ).
filter_list(L,OutList):-findall(X, (member(X,L),count(X,L,N),N=:=1) , OutList).
count(_,[],0).
count(X,[X|T],N):-count(X,T,N1),N is N1+1.
count(X,[X1|T],N):-dif(X,X1),count(X,T,N).
The predicate filter_list/2 uses findall/3 and simply states find all X that belong to the list L and count returns 1 and store them in OutList.
Example:
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
You could write filter_list/2 without using findall/3 like:
filter_list(L,OutList):- filter_list(L,OutList,L).
filter_list([],[],_).
filter_list([H|T],[H|T1],L):-count(H,L,N), N=:=1, filter_list(T,T1,L).
filter_list([H|T],T1,L):-count(H,L,N), N > 1, filter_list(T,T1,L).

In a List of Lists, Append all Lists together into one List

I need to write a predicate partition/2 such that partition(L, P) is satisfied when the concatenation of every List in the List of Lists P is the same as list L. The List of Lists P can contain an arbitrary number of Lists.
Example queries:
? - partition ([1 ,2 ,3] , P ).
P = [[1] , [2] , [3]];
P = [[1] , [2 , 3]];
P = [[1 , 2] , [3]];
P = [[1 , 2 , 3]];
no
? - partition (L , [[1] ,[2] ,[3 ,4 ,5]]).
L = [1 , 2 , 3 , 4 , 5];
no
I tried concatenating the lists in P together then checking to see if it is equal to L. This is what I have so far but it doesn't work. It loops indefinitely for any P that contains more than 1 list.
partition([], []). ;; Partition of empty list is the empty list
partition(L, [L]). ;; Base case where if P contains 1 element (list), L is equal to this list.
partition(L, [X|[Y1|Y2]]) :-
append(X, Y1, XY1),
partition(L, [XY1|Y2]). ;; Append each list in P to the list after it, repeating until one list is created. X is the head of the list, Y1 is the second element, and Y2 is the rest of the list.
Any help is appreciated.
The tricky part of this is to use append/3 in a way that universally terminates.
Let's code list_sublists/2 (a somewhat more declarative name than partition):
list_sublists([],[]).
list_sublists([X|Xs],[[Y|Ys]|Yss]) :-
append([Y|Ys],Xs0,[X|Xs]),
list_sublists(Xs0,Yss).
Consider the goal append([Y|Ys],Xs0,[X|Xs]) in the second clause: it terminates universally when either [Y|Ys] or [X|Xs] (or both) are/is bounded in length.
Now let's run the queries you gave:
?- list_sublists([1,2,3],Pss).
Pss = [[1],[2],[3]] ;
Pss = [[1],[2,3]] ;
Pss = [[1,2],[3]] ;
Pss = [[1,2,3]] ;
false.
?- list_sublists(Ls,[[1],[2],[3,4,5]]).
Ls = [1,2,3,4,5].
I tried to minimally correct your code: it ends up to something very similar (identical, really) to #repeat answer (+1), of course
partition([], []). % Partition of empty list is the empty list
%partition(L, [L]). % Base case where if P contains 1 element (list), L is equal to this list.
% Append each list in P to the list after it, repeating until one list is created. X is the head of the list, Y1 is the second element, and Y2 is the rest of the list.
partition(L, [[X|Xs]|Zs]) :-
append([X|Xs], Ys, L),
partition(Ys, Zs).
I would say the trick it's forcing the first argument of append/3 to have length > 0, accomplished giving it the pattern [X|Xs] instead of simply Xs

Extracting sequences (Lists) Prolog

Given a list eg [1,2,3,7,2,5,8,9,3,4] how would I extract the sequences within the list?
A sequence is defined as an ordered list (Normally I would say n-tuple but I have been told in prolog a tuple is referred to as a sequence). So we want to cut the list at the point where the next element is smaller than the previous one.
So for the list [1,2,3,7,2,5,8,9,3,4] it should return:
[ [1,2,3,7], [2,5,8,9], [3,4] ] %ie we have cut the list at position 4 & 8.
For this exercise you CANNOT use the construct ; or ->
Many thanks in advance!
EXAMPLE RESULTS:
eg1.
?-function([1,2,3,7,2,5,8,9,3,4],X): %so we cut the list at position 4 & 9
X = [ [1,2,3,7], [2,5,8,9], [3,4] ].
eg2.
?-function([1,2,3,2,2,3,4,3],X): %so we cut the list at position 3,4 & 8
X = [ [1,2,3], [2], [2,3,4], [3] ].
Hopefully that helps clarify the problem. If you need further clarification just let me know! Thanks again in advance for any help you are able to provide.
First, let's break it down conceptually. The predicate list_ascending_rest/3 defines a relation between a list Xs, the left-most ascending sublist of maximum length Ys, and the remaining items Rest. We will use it like in the following query:
?- Xs = [1,2,3,7,2,5,8,9,3,4], list_ascending_rest(Xs,Ys,Rest).
Ys = [1,2,3,7],
Rest = [2,5,8,9,3,4] ;
false.
The straight-forward predicate definition goes like this:
:- use_module(library(clpfd)).
list_ascending_rest([],[],[]).
list_ascending_rest([A],[A],[]).
list_ascending_rest([A1,A2|As], [A1], [A2|As]) :-
A1 #>= A2.
list_ascending_rest([A1,A2|As], [A1|Bs], Cs) :-
A1 #< A2,
list_ascending_rest([A2|As], Bs,Cs).
Then, let's implement predicate list_ascendingParts/2. This predicate repeatedly uses list_ascending_rest/3 for each part until nothing is left.
list_ascendingParts([],[]).
list_ascendingParts([A|As],[Bs|Bss]) :-
list_ascending_rest([A|As],Bs,As0),
list_ascendingParts(As0,Bss).
Example queries:
?- list_ascendingParts([1,2,3,7,2,5,8,9,3,4],Xs).
Xs = [[1,2,3,7], [2,5,8,9], [3,4]] ;
false.
?- list_ascendingParts([1,2,3,2,2,3,4,3],Xs).
Xs = [[1,2,3], [2], [2,3,4], [3]] ;
false.
Edit 2015/04/05
What if the ascending parts are known but the list is unknown? Let's find out:
?- list_ascendingParts(Ls, [[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ? ;
no
And let's not forget about the most general query using list_ascendingParts/2:
?- assert(clpfd:full_answer).
yes
?- list_ascendingParts(Ls, Ps).
Ls = [], Ps = [] ? ;
Ls = [_A], Ps = [[_A]] ? ;
Ls = [_A,_B], Ps = [[_A],[_B]], _B#=<_A, _B in inf..sup, _A in inf..sup ? ...
Edit 2015-04-27
Room for improvement? Yes, definitely!
By using the meta-predicate splitlistIfAdj/3 one can "succeed deterministically" and "use non-determinism when required", depending on the situation.
splitlistIfAdj/3 is based on if_/3 as proposed by #false in this answer. So the predicate passed to it has to obey the same convention as (=)/3 and memberd_truth/3.
So let's define (#>)/3 and (#>=)/3:
#>=(X,Y,Truth) :- X #>= Y #<==> B, =(B,1,Truth).
#>( X,Y,Truth) :- X #> Y #<==> B, =(B,1,Truth).
Let's re-ask above queries, using splitlistIfAdj(#>=)
instead of list_ascendingParts:
?- splitlistIfAdj(#>=,[1,2,3,7,2,5,8,9,3,4],Pss).
Pss = [[1,2,3,7],[2,5,8,9],[3,4]]. % succeeds deterministically
?- splitlistIfAdj(#>=,[1,2,3,2,2,3,4,3],Pss).
Pss = [[1,2,3],[2],[2,3,4],[3]]. % succeeds deterministically
?- splitlistIfAdj(#>=,Ls,[[3,4,5],[4],[2,7],[5,6],[6,8],[3]]).
Ls = [3,4,5,4,2,7,5,6,6,8,3] ; % works the other way round, too
false. % universally terminates
Last, the most general query. I wonder what the answers look like:
?- splitlistIfAdj(#>=,Ls,Pss).
Ls = Pss, Pss = [] ;
Ls = [_G28], Pss = [[_G28]] ;
Ls = [_G84,_G87], Pss = [[_G84],[_G87]], _G84#>=_G87 ;
Ls = [_G45,_G48,_G41], Pss = [[_G45],[_G48],[_G41]], _G45#>=_G48, _G48#>=_G41
% and so on...
maplist/3 as suggested in the comment won't help you here because maplist/3 is good at taking a list and mapping each element into a same-size collection of something else, or establishing a relation evenly across all of the individual elements. In this problem, you are trying to gather contiguous sublists that have certain properties.
Here's a DCG solution. The idea here is to examine the list as a series of increasing sequences where, at the boundary between them, the last element of the prior sequence is less than or equal to the first element of the following sequence (as the problem statement basically indicates).
% A set of sequences is an increasing sequence ending in X
% followed by a set of sequences that starts with a value =< X
sequences([S|[[Y|T]|L]]) --> inc_seq(S, X), sequences([[Y|T]|L]), { X >= Y }.
sequences([S]) --> inc_seq(S, _).
sequences([]) --> [].
% An increasing sequence, where M is the maximum value
inc_seq([X,Y|T], M) --> [X], inc_seq([Y|T], M), { X < Y }.
inc_seq([X], X) --> [X].
partition(L, R) :- phrase(sequences(R), L).
| ?- partition([1,2,3,4,2,3,8,7], R).
R = [[1,2,3,4],[2,3,8],[7]] ? ;
(1 ms) no
| ?- partition([1,2,3,2,2,3,4,3],X).
X = [[1,2,3],[2],[2,3,4],[3]] ? ;
(1 ms) no
The only reason for the rule sequences([]) --> []. is if you want partition([], []) to be true. Otherwise, the rule isn't required.

Resources