Prolog: how to remove every second list item

I need to write a program in Prolog that should remove every second element of the list. This should work: [1,2,3,4,5,6,7] β†’ [1,3,5,7]

So far I have it, but it just returns false.

  r ([], []). 
 r ([H | [T1 | T]], R): - del (T1, [H [T1 | T]], R), r (R).

 del (X, [X | L], L).
 del (X, [Y | L], [Y | L1]): - del (X, L, L1).
+4
source share
5 answers

This is pretty much Landei's answer in the specific Prolog syntax:

r([], []). r([X], [X]). r([X,_|Xs], [X|Ys]) :- r(Xs, Ys). 

A second predicate is not required.

+7
source

Alternative solution using foldl / 4 :

 fold_step(Item, true:[Item|Tail], false:Tail). fold_step(_Item, false:Tail, true:Tail). odd(List, Odd) :- foldl(fold_step, List, true:Odd, _:[]). 

Using:

 ?- odd([1, 2, 3, 4, 5, 6, 7], Odd). Odd = [1, 3, 5, 7] 

The idea is to go through the list, keeping the "odd / even" flag and throwing its value (false β†’ true, true β†’ false) for each element. We also gradually create a list, adding those elements for which the flag "odd / even" is true, and skip the others.

+4
source

This fine answer by @ code_x386 uses difference-lists and foldl/4 .

Let us use only one fold_step/3 and make the relation more general, for example:

 fold_step(X, [X|Xs]+Ys, Ys+Xs). list_odds_evens(List, Odds, Evens) :- foldl(fold_step, List, Odds+Evens, []+[]). 

Request examples:

 ?– list_odds_evens([a,b,c,d,e,f], Odds, Evens). Evens = [b,d,f], Odds = [a,c,e] ?– list_odds_evens([a,b,c,d,e,f,g], Odds, Evens). Evens = [b,d,f], Odds = [a,c,e,g] 

Edit

Why not use one less clause and end the fold_step/3 predicate? to the rescue!

<Preview>: - use_module ( library (lambda) ). list_odds_evens (List, Odds, Evens): - foldl (\ X ^ ([X | Xs] + Ys) ^ (Ys + Xs) ^ true, List, Odds + Evens, [] + []).
+3
source

Another possibility is to use DCG, they usually make sense when describing lists:

 list_oddindices(L,O) :- phrase(oddindices(L),O). % the list O is described by oddindices//1 oddindices([]) --> % if L is empty []. % O is empty as well oddindices([X]) --> % if L has just one element [X]. % it in O oddindices([O,_E|OEs]) --> % if L head consists of at least two elements [O], % the first is in O oddindices(OEs). % the same holds for the tail 

This, of course, is less elegant than solutions using foldl / 4, but the code is very easy to read, but it solves the problem described by OP and works in both directions:

 ?- list_oddindices([1,2,3,4,5,6,7],O). O = [1, 3, 5, 7] ; false. ?- list_oddindices(L,[1,3,5,7]). L = [1, _G4412, 3, _G4418, 5, _G4424, 7] ; L = [1, _G4412, 3, _G4418, 5, _G4424, 7, _G4430] ; false. 
+2
source

I don’t have Prolog here to try, and I did a little work, but it should be in lines

 r([]) :- []. r([X]) :- [X]. r([X,Y|Z]) :- R=r(Z),[X|R]. 

[change]

Of course, the panel is suitable. My solution will work in functional languages ​​like Haskell or Erlang:

 --Haskell r [] = [] r [x] = [x] r (x:_:xs) = x : (r xs) 

In Prolog, you need to "pull" the right parts into an argument list to cause unification.

0
source

All Articles