Reputation: 33
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
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
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
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
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