遍历Prolog中的列表

时间:2013-02-07 18:21:35

标签: prolog

我遇到这样的问题:查找列表中的所有元素,使得除此之外的所有元素都是奇数。

例如

?- find([20,1,2,3,4,5,6,7,8,10], L).
L = [20, 2, 4, 6]

通常在其他语言中我会遍历列表并检查条件,但我不知道在这种情况下如何在Prolog中“思考”。我该怎么做呢?

2 个答案:

答案 0 :(得分:3)

考虑一对头元素访问列表:

find([A,B|R], [A|T]) :-
   is_odd(B),
   ... etc etc

你需要明显添加基本递归情况和必须丢弃A的情况。

答案 1 :(得分:1)

编辑:基于CapelliCs建议的更好解决方案(这使用下面的isodd谓词):

% if N0 and N2 are odd, cut, add N1 to the result and recurse
ff([N0,N1,N2|T], [N1|R]) :- isodd(N0), isodd(N2), !, ff([N1,N2|T], R).
% for any other case where the list has at least three members, cut and recurse
ff([_,N1,N2|T], R) :- !, ff([N1,N2|T], R).
% this is reached if the list has less that three members - we're done
ff(_, []).

% append and prepend '1' to the list to deal with the edges, call ff.
find(L, R) :- append(L, [1], L1), ff([1|L], R).

我的旧解决方案,用额外的参数跟踪前两个值:

% isodd(+N)
% helper predicate that succeds for odd numbers.
isodd(N) :- mod(N, 2) =:= 1.

% find(+I, +N1, +N2, +R, -L)
% find/5 is the predicate doing the actual work.
% I is the input list, N1 and N2 are the numbers before the current one,
% R is the intermediate result list and L the result.

% we're done if the input list is empty
find([], _, _, R, R) :- !.

% check if N0 and N2 are odd to see if N1 should be appended to the list.
% if yes, do a cut, append N1 to the result and recurse.
find([N0|T], N1, N2, R, L) :-
   isodd(N0), isodd(N2), !, 
   append(R, [N1], R1), find(T, N0, N1, R1, L).

% if N0 and N2 are not odd (and thus the cut in the previous clause isn't
% reached) just continue the recursion.
find([N0|T], N1, _, R, L) :- find(T, N0, N1, R, L).

% find(+I, -L)
% this predicate is the entry point - initialize the result list and the first
% values for N1 and N2, and append 1 to the input list so we don't need an extra
% predicate for dealing with the last item.
find(I, L) :- append(I, [1], I1), find(I1, 1, 0, [], L).