John_00
John_00

Reputation: 45

Prolog take a part of a list

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

Answers (5)

Nicholas Carey
Nicholas Carey

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

CapelliC
CapelliC

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

TA_intern
TA_intern

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

slago
slago

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

Reema Q Khan
Reema Q Khan

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

Related Questions