Decompose list into lists of successive subsequences - list

I am really sorry for previous question, it's my first time post question on this website and I really didn't know I shouldn't post quesion like that.
It was my first time using prolog. Actually I spent more than 5 hours on this question but still cannot fully solve it, I tried to tear this question apart and here is what remain to be solved:
How to put the successive increasing whole numbers into a sublist in origin list.
eg. [3,5,1,2,3,7,8,2] to [3,5,[1,2,3],[7,8],2]
Here is what I wrote, can someone tell me how to fix the code? Thanks.
% empty List
chop_up([], []).
% single item list
chop_up([X], [X]).
% continue if the first number is not part of a sequence
chop_up(List, NewList):-
List = [First | Tail],
Tail = [Second | _],
First =\= Second - 1,
chop_up(Tail, NewList2),
NewList = [First | NewList2].
% if it is part of a sequence
chop_up(List, NewList):-
List = [First | Tail],
Tail = [Second | Tail2],
First is Second - 1,
chop_up(Tail, NewList2),
NewList = [[First] | NewList2].
enter image description here

Thank you for updating your question to show us what you tried!
Like all Prolog beginners, you are trying to do too much at once. This is normal! But you have to learn and get used to a way of thinking that is different from other programming languages. Almost always you have to decompose your problem into several subproblems that you then put together to get the final program.
So let's try to solve only one part of the problem first: Given a nonempty list, decompose it into successive elements at the front and into all the remaining elements. That is, we want something like this:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest).
Succ = [1, 2],
Rest = [4, 3] .
If we can write this definition, then we should be able to iterate over the Rest to chop it up further.
Here is a definition of list_successive_rest/3. Note how it follows the structure of your attempt for chop_up/2, but it's shorter and simpler because we only look at a successive prefix of the list, not all of the list at once:
list_successive_rest([X], [X], []).
list_successive_rest([A, B | Xs], [A], [B | Xs]) :-
A + 1 =\= B.
list_successive_rest([A, B | Xs], [A | Successive], Rest) :-
A + 1 =:= B,
list_successive_rest([B | Xs], Successive, Rest).
(This is also simpler than your version because I match lists of at least two elements as [A, B | Xs] rather than [A | Tail] and Tail = [B | Tail2]. It's a good idea to get used to this syntax.)
We can call this successively to decompose a list into successive parts:
?- list_successive_rest([1, 2, 4, 3], Succ, Rest), list_successive_rest(Rest, Succ2, Rest2), list_successive_rest(Rest2, Succ3, Rest3).
Succ = [1, 2],
Rest = [4, 3],
Succ2 = [4],
Rest2 = Succ3, Succ3 = [3],
Rest3 = [] ;
false.
Defining chop_up/2 is now easy by using the above predicate to peel off successive prefixes of the list iteratively:
chop_up([], []).
chop_up(List, [Succ | Chopped]) :-
list_successive_rest(List, Succ, Rest),
chop_up(Rest, Chopped).
Note that chop_up/2 is recursive, and it uses list_successive_rest/3, which is recursive as well. Trying to write all this in one recursive predicate would be harder and lead to less readable code.
Let's try the above test, and your test case:
?- chop_up([1, 2, 4, 3], Chopped).
Chopped = [[1, 2], [4], [3]] ;
false.
?- chop_up([3,5,1,2,3,7,8,2], Chopped).
Chopped = [[3], [5], [1, 2, 3], [7, 8], [2]] ;
false.
This doesn't actually produce the exact format you wanted: Singleton elements are singleton lists rather than "naked" members of the outer list. I think this is better this way, but your teacher may disagree. In that case, changing this small detail is an exercise for you.

I conseived much more elegant way with DCG!
chunk_list([])-->[].
chunk_list([C|Rest])-->chunk(C),chunk_list(Rest).
chunk(Ret)-->[First],consecutive(First,Last),{First=:=Last->Ret is First;Ret = [First,Last]}.
consecutive(Prev,Last)-->[Current],{Current is Prev+1},consecutive(Current,Last).
consecutive(Prev,Prev)-->[].
Test:
?- phrase(chunk_list(R),[1,2,3,6,7,3,3,2,3,4,6],[]).
R = [[1, 3], [6, 7], 3, 3, [2, 4], 6]
maybe it could be reversible with more lavor.
I.E. convert [[1, 3], [6, 7], 3, 3, [2, 4], 6] into [1,2,3,6,7,3,3,2,3,4,6]

I also tried for my prolog training.
terrible program but does work anyway.
I tested this in ECLiPSe but it will work with few modification in other environment(may be only deleting :-lib(listut))
call like this:
chunk([4,5,6,3,4,4,57,3,4,5,7,2,3,4,5,7,7,54,3],Ret).
Program:
:-lib(listut).
chunk(List,Ans):-
chunk_sub(List,0,[],List1),
first_and_lasts(List1,Ans),
!.
chunk_sub([],_,Ret,Reverse):-reverse(Ret,Reverse),!.
chunk_sub([Current|Rest],Prev,[NowList|RetRest],Ret):-
Current =:= Prev+1,
append(NowList,[Current],NextList),
chunk_sub(Rest,Current,[NextList|RetRest],Ret).
chunk_sub([Current|Rest],_,NowList,Ret):-
chunk_sub(Rest,Current,[[Current]|NowList],Ret).
first_and_lasts([],[]):-!.
first_and_lasts([FirstList|RestLists],[Converted|RestRet]):-
length(FirstList,Len),
(
Len=:=1->
([OneElem]=FirstList,Converted=OneElem);
(
nth1(1,FirstList,Smallest),
nth1(Len,FirstList,Biggest),
Converted=[Smallest,Biggest]
)
),
first_and_lasts(RestLists,RestRet).

Finally I did it!
this is reversible(generalized) version.This program works cleverly.
It was very fun developing this.
Code:
chunk_list([])-->[],!.
chunk_list([Chunk|Rest])-->chunk(Chunk),!,chunk_list(Rest).
chunk([First,Last])-->sequence([First,Last]),{First<Last}. % sequence
chunk(Val)-->sequence([Val,Val]). % isolated number
sequence([First,Last])-->
{(number(First),number(Last))->First<Last;true},
[First],
{succ(First,Second)},sequence([Second,Last]).
sequence([Val,Val])-->[Val].
Test:
[eclipse 4]: phrase(chunk_list([2,[2,6],[3,5],3,7,[1,3]]),Ret).
Ret = [2, 2, 3, 4, 5, 6, 3, 4, 5, 3, 7, 1, 2, 3]
Yes (0.00s cpu)
[eclipse 5]: phrase(chunk_list(Ret),[3,4,5,2,1,6,7,88,9,4,5,6,7,2,1,2,3]).
Ret = [[3, 5], 2, 1, [6, 7], 88, 9, [4, 7], 2, [1, 3]]
Yes (0.00s cpu)
[eclipse 6]: phrase(chunk_list([[2,4],A,[2,8],3]),[2,B,4,6,2,C,4,5,6,7,D,E]).
A = 6
B = 3
C = 3
D = 8
E = 3
Yes (0.00s cpu)

Related

Prolog delete all increasing subseries from a list

The task is to delete all increasing subseries from a list. For example:
deleteInc([2,4,6,5,8,12,8,3],L) should produce L=[8,3] as result
I tried to solve it, but it's not working properly and I can't figure out the correct solving. Can somebody help me out please with a correct solution? Thanks in advance :)
My Code:
deleteInc([],[]).
deleteInc([H1,H2|T],L):-
H2>=H1,
!,
deleteInc(T,L).
deleteInc([H1,H2|T],[H2|T2]):-
H2<H1,
deleteInc(T,T2).
Here's what I did, assuming it's checking three values at a time:
deleteInc([],[]).
deleteInc([H1,H2,_H3|T],L):-
H2>=H1,
!,
deleteInc(T,L).
deleteInc([H1,H2|T],[H1,H2|T2]):-
H2<H1,!,
deleteInc(T,T2).
Example:
?-deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3]
?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L).
L = [7, 3]
?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L).
L = [65, 38]
Here's an approach to collect all combinations that are not increasing:
deleteInc(L,[],L).
deleteInc([H1,H2|T],L,Rest):-
H2>=H1,
!,
deleteInc(T,L,Rest).
deleteInc([H1,H2|T],[H1,H2|L],Rest):-
H2<H1,!,
deleteInc(T,L,Rest).
Example:-
?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 65, 38]
?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 25, 7]
?-deleteInc([2,4,6,5,8,12,8,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5, 8, 3]
I would implement it like this:
deleteInc(In, Out):-
deleteInc(In,Out,new).
deleteInc([A],[A],new).
deleteInc([_],[],incr).
deleteInc([H1,H2|T],L,_):-
H2>=H1,
!,
deleteInc([H2|T],L,incr).
deleteInc([H1,H2|T],T2,incr):-
H2<H1,
deleteInc([H2|T],T2,new).
deleteInc([H1,H2|T],[H1|T2],new):-
H2<H1,
deleteInc([H2|T],T2,new).
A third attribute indicates if your are currently in a new or increasing streak.
If the two head elements of the list are in increasing order, the third element is pretty much ignored. Please note to forward not the list T but [H2|T] since you need the element H2 for further comparison. If you are in a streak (incr) and the current two head elements are not increasing, you do the same as before: ignore. However if you just started a new streak and the current head elements are decreasing, you put the first head element in the return list. Special cases for one element. Let's check:
?- deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3] ;
false.
Looks good.
Another approach would be to just check for 3 succeeding elements if the middle one is smaller than the first but larger than the third. If this is the case: store the element. If this is is not the case: check the list without the first head element.
Add a rule for 2 elements left. Also there needs to be a special treatment for the very first element, because this is not covered in the main rule. By using the cut you can "catch" the left over case (two increasing elements or weird input with one or no element) with the last line. Please note that the order of the rules is important for the program to work.
deleteInc([H1,H2|L], [H1|R]):-
H1 >= H2,
!,
deleteInc1([H1,H2|L], R).
deleteInc([H1,H2|L], R):-
deleteInc1([H1,H2|L], R).
deleteInc1([H1,H2,H3|L], [H2|R]):-
H1 > H2,
H2 > H3,
!,
deleteInc1([H2,H3|L], R).
deleteInc1([A,B],[B]):-
A > B,
!.
deleteInc1([_|L], R):-
!,
deleteInc1(L, R).
deleteInc1(_,[]).
Let's test it:
?- deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3].
Works (for lists of numbers).
And yet another solution would be to count the length of the streak and to filter out all results which have more than one element. The following code starts with count 0 for the first element and uses the successor predicate s/1 for counting:
deleteInc(In, Out):-
countInc(In,0,InC),
delInc(InC,Out).
countInc([A], C, [(A,C)]).
countInc([A,B|L], C, Out):-
A =< B,
countInc([B|L], s(C), Out).
countInc([A,B|L], C, [(A,C)|Out]):-
A > B,
countInc([B|L], 0, Out).
delInc([],[]).
delInc([(E,0)|L],[E|R]):-
delInc(L,R).
delInc([(_,s(_))|L],R):-
delInc(L,R).
Output:
?- deleteInc([2,4,6,5,8,12,8,3],L)
L = [8, 3] ;
false.
As expected

Most common sublist in Prolog

The problem is as follows: Write a predicate in Prolog most_common_sublist(L1,N,L2) that will find the sublist L2 with length N such that it is the most common sublist in L1.
//Example 1:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],1,L).
L=[2];
//Example 2:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],2,L).
L=[2,2];
//Example 3:
?- most_common_sublist([1,2,2,3,2,2,4,2,2,3],3,L).
L=[2,2,3];
My approach was to generate all the possible sublists of size N using the generator predicate, check which of those is the most common one in the list using the check predicate, and then just put that as my result.
The reason why I'm not using the built-in predicates for length and add is because I'm supposed to write my own.
My generator predicate works, it gives out the correct output.
?- generator([1,2,2,3,2,2,4,2,2,3],3,L).
L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2|...], [2|...]] [write]
L = [[1, 2, 2], [2, 2, 3], [2, 3, 2], [3, 2, 2], [2, 2, 4], [2, 4, 2], [4, 2, 2], [2, 2, 3]]
I checked all my predicates and they all seem to work (at least for the test cases I'm using), the problem occurs with the check predicate. It seems to work fine until it gets to N>=P (when this is NOT true, works fine when it is true). I expect the program to go onto the next check predicate under it (the third check predicate) so that it stores Temp value in Result instead of the H value. For some reason it does not go to the third check predicate (I checked with debugger), instead it does something weird (I can't figure out what).
most_common_sublist(L,N,Result):-generator(L,N,LOP),check(LOP,_,Temp),add(Temp,[],Result).
add([],L,L).
add([X|L1],L2,[X|L3]):-add(L1,L2,L3).
length([],0).
length([X|O],N):-length(O,M),N is M+1.
sublist([H|_],1,[H]).
sublist([H|T],N,[H|LOP]):-M is N-1,sublist(T,M,LOP).
generator(L,N,[L]):-length(L,M),N=:=M.
generator([H|T],N,LOP):-sublist([H|T],N,PN),generator(T,N,LP),add([PN],LP,LOP).
check([],Z,K):-Z is 0,add([],[],K).
check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,_),N>=P,Hits is N,add(H,[],Result).
check([H|T],Hits,Result):-check_how_many(H,[H|T],N),check(T,P,Temp),Hits is P,add(Temp,[],Result).
check_how_many(X,[X],1).
check_how_many(_,[_],0).
check_how_many(Pattern,[H|T],Hits):-same(Pattern,H),check_how_many(Pattern,T,P),Hits is P+1.
check_how_many(Pattern,[_|T],Hits):-check_how_many(Pattern,T,P),Hits is P.
same([], []).
same([H1|R1], [H2|R2]):-
H1 = H2,
same(R1, R2).
Since I'm not familiar with your code I rewrote it with similar functionality. Lines followed by %here are my improvements (2 times used). For simplicity I used the inbuild predicates length/2 and append/3 instead of add/3. sublist/3 has a complete different code but same functionality, same/2 is not necessary at all. Most uses of you add/3 were not necessary as well as some equality statements.
most_common_sublist(L,N,Temp):-
generator(L,N,LOP),
check(LOP,_,Temp).
sublist(L,N,S):-
length(S,N),
append(S,_,L).
generator(L,N,[L]):-
length(L,N).
generator([H|T],N,LOP):-
sublist([H|T],N,PN),
generator(T,N,LP),
append([PN],LP,LOP).
check([],0,[]).
check([H|T],N,H):-
check_how_many(H,[H|T],N),
check(T,P,_),
N>=P.
check([H|T],P,Temp):-
check_how_many(H,[H|T],N),
check(T,P,Temp)
%here
, N=<P
.
check_how_many(X,[X],1).
check_how_many(_,[_],0).
check_how_many(H,[H|T],Hits):-
check_how_many(H,T,P),
Hits is P+1.
check_how_many(Pattern,[H|T],P):-
%here
Pattern \== H,
check_how_many(Pattern,T,P).
After giving up on tracing I just used the following call to debug after enabling long output (
?- set_prolog_flag(answer_write_options,[max_depth(100)]).
):
?- findall(Temp,check([[1, 2, 2], [2, 2, 1]],_,Temp),Out).
Initial output was
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[],[],[2,2,1],[2,2,1],[],[]].
Which contains way to much empty lists. First fix (%here) was to set the condition N=<P for the last check/3 case. Until now it was possible to choose a P lower than N, which should be covered by the 2nd check/3 case. Output changed to
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,1],[2,2,1],[2,2,1],[]].
Better, but still empty lists possible. A similar case happens in the last check_how_many/3 case: you have to state that H and Pattern are different, otherwise it would be possible for a fitting Pattern not to be counted. Lets check the output
Out = [[1,2,2],[1,2,2],[1,2,2],[2,2,1]].
Way better. Lets check another case:
?- findall(Temp,check([[1, 2, 2], [1, 2, 2], [2, 2, 1]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2]].
?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[2,2,2],[2,2,2],[2,2,2],[1,2,2]].
Works... Almost.
So the problem seems to be check_how_many/3: alter
check_how_many(_,[_],0).
to
check_how_many(_,[],0).
and you should be fine.
?- findall(Temp,check([[1, 2, 2], [2, 2, 2], [1, 2, 2]],_,Temp),Out).
Out = [[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2],[1,2,2]].
Since it is way more fun to write the code yourself than to debug foreign code I'll add another answer with my attempt.
It is way more fun to code by yourself than to debug alien code. So here is my attempt. It works different than yours because I do not calculate possible subsets but work on the "leftover" list. I use the inbuild predicates length/2, append/3 and member/2 which are 3 lines each to write down.
% check how often 2.nd attribute List occurs in 1st attribute List.
countit([],_,Val,Val).
countit([H|In],Out,Past,Future):-
( append(Out,_,[H|In])
-> Present is Past+1,
countit(In,Out,Present,Future)
; countit(In,Out,Past,Future)
).
mostCommonSublist(In,N,Out):-
maxStartList(In,N,OutList,Max),
member((Max,Out),OutList).
% for every endlist calculate how often the first N elements appear within the endlist, track the max
maxStartList(In,N,[(1,In)],1):-
length(In,N),
!.
maxStartList([H|In],N,[(CntH,Curr)|MaxList],Max):-
length(Curr,N),
countit([H|In],Curr,0,CntH),
maxStartList(In,N,MaxList,CntIn),
Max is max(CntH , CntIn).
The main predicate mostCommonSublist/3 calls the predicate maxStartList/4 to get all sublists/countpairs. Afterwards it validates if the count of a sublist equals the maximum. This is neccessary to check for different answers with the same (maximum) count.
The maxStartList/4 drops elements from the inputlist and counts how often the start of the current list occurs within it. Also it keeps track of the maximum.
For the current inputlist the calculating predicate countit/4 is called. It calculated for a given inputlist (first argument) the number of occurences of a sublist (2nd argument).
My code actually uses a twist: The content of the sublist is not unified when calling countit/4 for the first time, just the sublist length is set. In the first recursion it will unify all entries with the start elements from the inputlist and count it. In the following recursion steps the sublist if fully known. Using an if-then-else (..->..;..) the two cases for remaining inputlist starts with the sublist or not, the predicate basically counts the occurences. Until the remaining inputlist has only N elements left (length(In,N)).
The calculated count/sublist pairs are stored in a list, the maximum is tracked as well.
After knowing all count/sublist pairs I finallize it all by stating that the count of an accepted sublist has to be equal to the maximum.
The nice thing is that there are no dublicate answers.
?- mostCommonSublist([1,2,2,3,2,2,4,2,2,3],3,L).
L = [2,2,3] ;
false.
?- mostCommonSublist([1,2,2,1,2,1,2,2,2,3],3,L).
L = [1,2,2] ;
L = [2,1,2] ;
false.
?- mostCommonSublist([1,2,2,1,2,1,2,2,2,1],2,L).
L = [1,2] ;
L = [2,2] ;
L = [2,1] ;
false.

Prolog - Creating a list of all the possible shifts of another list?

For my assignment I need to create a list of all the possible shifts (rotations) of another list in prolog. For example,
Prototype: all_shifts(+A,-R,+L,+S) *S will always start at 1*
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]].
Currently, I have a program that shifts it to the left once.
one_shift(A, R) :-
rotate(left, A, R).
rotate(left, [H|T], L) :- append(T, [H], L).
However, I need to create another program in which the final result (R) contains all of the possible shifts. Recursion in prolog is really beginning to confuse me, but I'm pretty sure that's whats required. Any help would be really appreciated.
Stay logically pure using same_length/2 and append/3!
list_rotations(Es, Xss) :-
same_length(Es, [_|Xss]),
rotations_of(Xss, Es).
rotations_of([], _Es).
rotations_of([Xs|Xss], Es) :-
same_length([_|Xss], Suffix),
same_length(Es, Xs),
append(Suffix, Prefix, Xs),
append(Prefix, Suffix, Es),
rotations_of(Xss, Es).
Sample query:
?- list_rotations([A,B,C,D], Xss).
Xss = [[B,C,D,A],
[C,D,A,B],
[D,A,B,C]]. % succeeds deterministically
A solution to your problem could be:
rotatelist([H|T], R) :- append(T, [H], R).
rotate(L,LO,LL):-
rotatelist(L,L1),
\+member(L1,LO),!,
append([L1],LO,L2),
rotate(L1,L2,LL).
rotate(_,L,L).
?- rotate([1,2,3,4],[],L).
L = [[1, 2, 3, 4], [4, 1, 2, 3], [3, 4, 1, 2], [2, 3, 4, 1]]
Simply rotates the list and checks if this list has already been inserted in the output list. If not the recursion continues, otherwise it returns the list in L. I've inserted the cut ! just to have only the list with all the possible rotations. If you want generate also the other lists just remove it...
If instead you want a solution with the prototype you provide, it could be:
rotatelist([H|T], R) :- append(T, [H], R).
all_shifts(_,[],I,I).
all_shifts(L,Result,Len,I):-
I < Len,
rotatelist(L,LO),
I1 is I+1,
all_shifts(LO,R1,Len,I1),
append([LO],R1,Result).
?- length([1,2,3,4],L), all_shifts([1,2,3,4],R,L,1).
L = 4,
R = [[2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The idea is basically the same as before... Note that this second solution is not tail recursive.

Prolog: Generating Every Possibility of a List Given a Pattern

Let's say you have a list in Prolog such as: [3,4,2,2,1,4]. How would one go about generating a list of lists of all possible patterns that start at the first element of the list, then either go to the i + 2th element, or the i + 3rd element, and so on from there.
Example:
Say I have [3,4,2,2,1,4,8].
I want to be able to generate a list of lists such as:
[[3,2,1,8], [3,2,4], [3,2,8]]
I.e. all possibilities of either every other element or every i+3 element, or any other combination, such as i+2,i+3,i+2,i+2, etc.
I've implemented my own version of a powerset, but I can't seem to figure out where to start.
gen([], []).
gen([A], [A]).
gen([A, _ | T], [A | Xs]) :- gen(T, Xs).
gen([A, _, _ | T], [A | Xs]) :- gen(T, Xs).
results in
?- gen([3,4,2,2,1,4,8], X).
X = [3, 2, 1, 8] ;
X = [3, 2, 1] ;
X = [3, 2, 4] ;
X = [3, 2, 4] ;
X = [3, 2, 8] ;
false.
You can use findall/3 to get all results
?- findall(X, gen([3,4,2,2,1,4,8], X), Z).
Z = [[3, 2, 1, 8], [3, 2, 1], [3, 2, 4], [3, 2, 4], [3, 2, 8]].

Prolog how do I append a list of lists into one list?

So I'm totally new to Prolog and need some help. I'm trying to take a list of lists like [[1,2,3],[4,5,6],[7,8]] and create a list like [2,3,5,6,8], so basically all the values into a new list besides the first of each list. I got this:
test5(X,[[_|X]|_]).
test5(X,[_|A]) :- test5(X,A).
which returns [2,3] and then [5,6] and then [8] each time I press enter. I'm not sure how to make them run all at once and make them into a list. I tried using append in different ways but I could not get this working. Any idea on how to implement this? Thanks!
You have the common predicate flatten/2, which almost does the job:
?- flatten([[1,2,3],[4,5,6],[7,8]], L).
L = [1, 2, 3, 4, 5, 6, 7, 8].
There are many implementations of flatten/2 available, just google it.
If you know that the list of lists is not nested, you should rather use append/2.
Then, you need to drop the first element of each list before appending:
list_tail([_|T], T).
Then:
?- maplist(list_tail, [[1,2,3],[4,5,6],[7,8]], T), append(T, L).
T = [[2, 3], [5, 6], [8]],
L = [2, 3, 5, 6, 8].
It might be a good exercise to take a more careful look at the implementation of append/2 linked above. With a small change in the definition (literally removing 1 character and adding 5) it will do the dropping and appending in the same step, without traversing the original list twice.
EDIT
So why is it that #repeat's initial solution does not terminate when the first argument is not a proper list, but the second is a proper list?
nt_tails_append([[_|T]|Ls], As) :-
append(T, Ws, As),
nt_tails_append(Ls, Ws).
It is because when the first argument to nt_tails_append/2 is a free variable, the first two arguments to append/3 above are variables, too. When we call append/3 in this mode, we get, by definition:
?- append(A, B, L).
A = [],
B = L .
In other words, the second and the third arguments are now unified. With the definition of nt_tail_append/2, this means that the recursive call gets the same second argument as the original call, and a new free variable as the first argument. This is an endless loop, of course.
(Tellingly, if you care to look at the definition of append/2 linked above, you will see that the first argument must_be a list.)
How does this help?
tails_append(Ls, As) :-
maplist(list_tail, Ls, T),
append(T, As).
list_tail([_|T], T).
The way that maplist is defined, all list arguments will be instantiated to proper lists. So you can safely use append/3 (here, used in the definition of append/2).
Here is how you could do it using append/3:
lists_concatenatedTails([],[]).
lists_concatenatedTails([[_|Xs0]|Xss],Ys) :-
append(Xs0,Ys0,Ys),
lists_concatenatedTails(Xss,Ys0).
Sample query:
?- lists_concatenatedTails([[1,2,3],[4,5,6],[7,8]], Xs).
Xs = [2, 3, 5, 6, 8].
Edit 2015-05-07
Note that the code that #Boris suggested (using list_tail/2,maplist/3,append/2) also gives answers for the following query:
?- maplist(list_tail,Xss,Yss), append(Yss,[1,2,3]).
Xss = [[_G97, 1, 2, 3]], Yss = [[1, 2, 3]] ;
Xss = [[_G97], [_G106, 1, 2, 3]], Yss = [[], [1, 2, 3]] ;
Xss = [[_G97, 1], [_G106, 2, 3]], Yss = [[1], [2, 3]] ;
Xss = [[_G97, 1, 2], [_G106, 3]], Yss = [[1, 2], [3]] ;
Xss = [[_G97, 1, 2, 3], [_G106]], Yss = [[1, 2, 3], []] ;
Xss = [[_G97], [_G106], [_G115, 1, 2, 3]], Yss = [[], [], [1, 2, 3]] ...
This doesn't terminate universally---nor do we expect it to: the set of solutions is infinite in size and it can, in this case, only be covered by an infinite sequence of answers.
In the following equivalent query lists_concatenatedTails/2 "loops" right away:
?- lists_concatenatedTails(Lss,[1,2,3]).
% not a single answer within finite time
Only when constraining the length of Lss right away, fair enumeration can be achieved:
?- length(Lss,_), lists_concatenatedTails(Lss,[1,2,3]).
Lss = [[_G23, 1, 2, 3]] ;
Lss = [[_G26], [_G29, 1, 2, 3]] ;
Lss = [[_G26, 1], [_G32, 2, 3]] ;
Lss = [[_G26, 1, 2], [_G35, 3]] ;
Lss = [[_G26, 1, 2, 3], [_G38]] ;
Lss = [[_G29], [_G32], [_G35, 1, 2, 3]] ...