Reputation: 45
How can I take a part of a list? example :
?- part([1,2,3,4,5,6,7,8,9],3,6,Χ).
X = [3,4,5,6]
The first element should be the start and the second should be the end.
Upvotes: 2
Views: 655
Reputation: 74365
Assuming that your start and end are indices into the list, this will work (assuming zero-based indices, where 0
is the index of the 1st element in the list:
part( List, X, Y, Part) :-
X >= 0,
Y >= X,
L is Y - X + 1,
length( Pfx , X ),
length( Part, L ),
append( Pfx, Sfx, List ),
append( Part, _, Sfx ).
Upvotes: 0
Reputation: 60034
If your Prolog has dif/2, you can generalize the snippet in this way
take_el_start_stop(L,X,Y,R) :-
phrase(take_el_start_stop(X,Y,R),L,_).
take_el_start_stop(X,Y,[X|R]) -->
[X], take_el_to_stop(Y,R).
take_el_start_stop(X,Y,R) -->
[Z], {dif(X,Z)}, take_el_start_stop(X,Y,R).
take_el_to_stop(Y,[Y]) --> [Y].
take_el_to_stop(Y,[Z|R]) -->
[Z],
% {dif(Y,Z)}, uncomment for a strict start/stop match
take_el_to_stop(Y,R).
edit
Didn't noticed the ambiguity in your question. Indeed, instead of values, the start and stop elements could be 1-based indexes as well. In that case, nth1/3 with findall/3 would work:
get_elems_between_start_and_stop(L,Start,Stop,R) :-
findall(E,(between(Start,Stop,I),nth1(I,L,E)),R).
Upvotes: 0
Reputation: 2436
This answer obviously takes the second and third arguments as indexes. But maybe they are meant to be values? This brings up a whole lot of other questions since indexes are unique, ordered and so on, while values can be just about anything.
This has been solved many times in different ways. Surely many solutions for this on Stackoverflow. One way is to use length/2 and append/3 twice:
?- List = [1,2,3,4,5,6,7,8,9],
length(Skip, 2), append(Skip, Rest, List),
length(Take, 4), append(Take, _, Rest).
Take = [3, 4, 5, 6].
You need to calculate the two lengths from the indices:
?- From = 3, To = 6,
N_skip is From - 1,
N_take is To - From + 1.
N_skip = 2,
N_take = 4.
The other way to do it is to count it down yourself, and that can be written in many different ways.
Upvotes: 4
Reputation: 5519
Supposing that the list has duplicate elements, a possible solution is:
part(List, Begin, End, Part) :-
append(_, [Begin|Rest], List), % suffix starting with Begin
append(Prefix, [End|_], [Begin|Rest]), % prefix of the suffix ending just before End
append(Prefix, [End], Part).
Here are some examples:
?- part([1,2,3,4,5,6,7,8,9],3,6,P).
P = [3, 4, 5, 6] ;
false.
?- part([10,11,12,13,1,4,1,5,16],13,16,P).
P = [13, 1, 4, 1, 5, 16] ;
false.
?- part([1,2,3],2,E,P).
E = 2,
P = [2] ;
E = 3,
P = [2, 3] ;
false.
?- part([1,2,3,4,5,3,6,7,8,6,9],3,6,P).
P = [3, 4, 5, 3, 6] ;
P = [3, 4, 5, 3, 6, 7, 8, 6] ;
P = [3, 6] ;
P = [3, 6, 7, 8, 6] ;
false.
Upvotes: 3
Reputation: 878
1- split predicate
takes the list [H|T], Start (Starting Number), Last (Last Number), and NewList.
2- s1 predicate
takes the Last Number and generates a whole List till the last number. Example: if 6 is the given last number from the List =[1,2,3,4,5,6,7,8,9], then s1 will give List=[1,2,3,4,5,6]
3- s2 predicate
will take the generated list from s1 ([1,2,3,4,5,6]), and using the Starting number (3) will discard all previous numbers and give us the remaining list. Example: s1 gives [1,2,3,4,5,6], s2 using start number 3 gives [3,4,5,6].
split([H|T],Start,Last,NewList):-
s1([H|T],Last,N1),
s2(N1,Start,NewList).
s1([H|T],LastN,[H|L]):-
H\=LastN,
s1(T,LastN,L).
s1([H|_],LastN,[LastN]):-
H=LastN,!.
s2([H|T],StartN,[H|T]):-
H=StartN.
s2([H|T],StartN,L):-
H\=StartN,
s2(T,StartN,L).
Example:
?- split([1,2,3,4,5,6,7,8,9],3,6,L).
L = [3, 4, 5, 6]
false
?- split([10,11,12,13,1,4,1,5,16],13,16,L).
L = [13, 1, 4, 1, 5, 16]
false
Upvotes: 1