J. East.
J. East.

Reputation: 33

Prolog: get and append every third item from a list to a new list

With the following piece of code in Prolog I managed to extract every third item from a list:

third([_,_,Z|L], Z).    
third([_,_,C|L], Y) :-
   third(L, Y).

However, I still need to append every item that I am extracting to a new list, and finally create a list with only "every third" items. I would appreciate any hint or help! Thank you.

Upvotes: 1

Views: 272

Answers (4)

lurker
lurker

Reputation: 58284

There's a DCG approach that would also work, analogous to @repeat's answer:

thirds([]) --> [].
thirds([]) --> [_].
thirds([]) --> [_,_].
thirds([X|T]) --> [_,_,X], thirds(T).

Or more concisely (thanks @repeat):

thirds([]) --> [] | [_] | [_,_].
thirds([X|T]) --> [_,_,X], thirds(T).

Called as follows:

| ?- phrase(thirds(T), [a,b,c,d,e,f,g,h]).

T = [c,f] ? a
no

| ?- phrase(thirds(T), L).

L = []
T = [] ? ;

L = [_]
T = [] ? ;

L = [_,_]
T = [] ? ;

L = [_,_,A]
T = [A] ? ;

L = [_,_,A,_]
T = [A] ? ;
...

Upvotes: 2

joel76
joel76

Reputation: 5645

With SWI-Prolog, and module lambda.pl, you can write

:- use_module(library(lambda)).
third(In, Out) :-
    foldl(\X^Y^Z^(Y=[N,L],
              (   N = 2
              ->  append(L, [X], NL),
              Z = [0,NL]
              ;   N1 is N+1,
              Z = [N1, L])),
          In, [0, []], [_, Out]).

With same queries :

 ?- third([1,2,3,4,5,6,7,8,9,10], Out).
Out = [3, 6, 9].

  ?- third(X, [3,6,9]).
X = [_G103, _G180, 3, _G352, _G438, 6, _G613, _G699, 9] ;
X = [_G103, _G180, 3, _G352, _G438, 6, _G613, _G699, 9|...] .

 ?- third(X, Y).
X = Y, Y = [] ;
X = [_G87231],
Y = [] ;
X = [_G87231, _G87317],
Y = [] ;
X = [_G87231, _G87317, _G87403],
Y = [_G87403] ;
X = [_G87231, _G87317, _G87403, _G87489],
Y = [_G87403] ;
X = [_G87231, _G87317, _G87403, _G87489, _G87575],
Y = [_G87403] ;
X = [_G87231, _G87317, _G87403, _G87489, _G87575, _G87661],
Y = [_G87403, _G87661] .

Upvotes: 2

repeat
repeat

Reputation: 18726

How about doing it like this?

list_thirds([]        , []).
list_thirds([_]       , []).
list_thirds([_,_]     , []).
list_thirds([_,_,E|Es], [E|Xs]) :-
   list_thirds(Es, Xs).

Sample queries using SICStus Prolog 4.3.2:

| ?- list_thirds([], Xs).
Xs = [] ? ;
no

| ?- list_thirds([a,b,c], Xs).
Xs = [c] ? ;
no

| ?- list_thirds([a,b,c,d,e,f], Xs).
Xs = [c,f] ? ;
no

| ?- list_thirds([a,b,c,d,e,f,g], Xs).
Xs = [c,f] ? ;
no

How about going the "other direction"?

| ?- list_thirds(List, [x,y]).
List = [_A,_B,x,_C,_D,y]       ? ;
List = [_A,_B,x,_C,_D,y,_E]    ? ;
List = [_A,_B,x,_C,_D,y,_E,_F] ? ;
no                                     % terminates universally

Last, we look at the answer sequence we get from the most general query:

| ?- list_thirds(Es, Xs).
Es = []                 , Xs = []      ? ;
Es = [_A]               , Xs = []      ? ;
Es = [_A,_B]            , Xs = []      ? ;
Es = [_A,_B,_C]         , Xs = [_C]    ? ;
Es = [_A,_B,_C,_D]      , Xs = [_C]    ? ;
Es = [_A,_B,_C,_D,_E]   , Xs = [_C]    ? ;
Es = [_A,_B,_C,_D,_E,_F], Xs = [_C,_F] ? ;
...

Upvotes: 5

Topological Sort
Topological Sort

Reputation: 2851

This will work:

 bagof(Third,third(List,Third),Result).

This collects all items Third such that Third is third in List; and binds the list of them to Result.

For more on bag, see http://www.swi-prolog.org/pldoc/doc_for?object=bagof/3 .

Upvotes: 1

Related Questions