如何在Prolog中预测给定列表中的所有对?

时间:2012-05-01 21:57:03

标签: list prolog combinations

当给出列表时,我想计算列表中所有可能的对组合。

例如2)输入是一个列表(a,b,c)我想获得对(a,b)(a,c)(b,c)

例如1)输入是一个列表(a,b,c,d)我想获得对(a,b)(a,c)(a,d)(b,c)(b,d)和(c,d)

4 个答案:

答案 0 :(得分:2)

使用select/3两次(或select/3一次,member/2一次)将允许您在此处实现您想要的效果。如果它仍然很麻烦,我会让你弄清楚细节并寻求帮助。

BTW,列表的Prolog语法不是(a, b, c)而是[a, b, c](好吧,它是语法糖,但我会留下它)。

修改:正如@WillNess指出的那样,您不是要寻找任何一对(X, Y),而只是寻找X之前的Y对的对列表。

DCG非常适合:如@false所述,它们可以产生graphically appealing solution

... --> [] | [_], ... .

pair(L, X-Y) :-
    phrase((..., [X], ..., [Y], ...), L).

或者,如果你使用SWI-Prolog,对append/2的调用也会以类似的方式解决问题,但效率低于DCG:

pair2(L, X-Y) :-
    append([_, [X], _, [Y], _], L).

你可以通过@WillNess在评论中提出的基本递归来实现。如果需要,我会留下这部分给他详细说明!

答案 1 :(得分:2)

好的,所以翻译Haskell的

pairs (x:xs) = [ (x,y) | y<-xs ]
                ++ pairs xs 
pairs []     = []

作为一个回溯的Prolog谓词,它是一个简单而简短的

pair([X|XS],X-Y):- member( ... ,XS).  %% fill in the '...' here
pair([_|XS],P) :- pair(XS, ... ).     %%
%% pair([],_) :- false. 

要获得所有可能的对,请使用findall

pairs(L,PS):- findall(P, pair(L,P), PS).

如果您的列表中包含逻辑变量,请考虑使用bagof。然而,控制bagof的回溯可能是一个复杂的问题。

pairs也可以写为确定性的,非回溯的递归定义,通过累加器参数构造其输出列表 - 这里以自上而下的方式,这使得它成为差异列表< / em>真的:

pairs([X|T],PS):- T=[_|_], pairs(X,T,T,PS,[]) ; T=[], PS=[].
pairs([],[]).

pairs(_,[],[],Z,Z).
pairs(_,[],[X|T],PS,Z):- pairs(X,T,T,PS,Z).
pairs(X,[Y|T],R,[X-Y|PS],Z):- pairs(X,T,R,PS,Z).

答案 2 :(得分:0)

这是解决此问题的一种可能方法。

以下谓词combine/3为真 如果第三个参数对应于一个列表 包含对,其中每个对的第一个元素 等于combine/3的第一个参数。 每对的第二个元素将对应一个项目 谓词combine/3的第二个参数中的列表。 combine/3应该如何工作的一些示例:

?- combine(a,[b],X).
X = [pair(a,b)]

?- combine(a,[b,c,d],X).
X = [pair(a,b), pair(a,c), pair(a,d)]

定义combine/3的可能方式:

combine(A,[B],[pair(A,B)]) :- !.

combine(A,[B|T],C) :-
  combine(A,T,C2),          % Create pairs for remaining elements in T.
  append([pair(A,B)],C2,C). % Append current pair and remaining pairs C2.
                            % The result of append is C.

现在combine/3可用于定义pair/2

pairs([],[]).      % Empty list will correspond to empty list of pairs.
pairs([H|T],P) :-  % In case there is at least one element.
  nonvar([H|T]),   % In this case it expected that [H|T] is instantiated.
  pairs(H,T,P).

pairs(A,[B],[pair(A,B)]) % If remaining list contains exactly one element,
  :- !.                  % then there will be only one pair(A,B).
pairs(A,[B|T],P) :-      % In case there are at least two elements.
  combine(A,[B|T],P2),   % For each element in [B|T] compute pairs
                         % where first element of each pair will be A.
  pairs(B,T,P3),         % Compute all pairs without A recursively.
  append(P2,P3,P).       % Append results P2 and P3 together.

样品用量:

?- pairs([a,b,c],X).
X = [pair(a, b), pair(a, c), pair(b, c)].

?- pairs([a,b,c,d],X).
X = [pair(a, b), pair(a, c), pair(a, d), pair(b, c), pair(b, d), pair(c, d)].

答案 3 :(得分:0)

您可以使用append/遍历列表:

?- append(_,[X|R],[a,b,c,d]).
X = a,
R = [b, c, d] ;
X = b,
R = [c, d] ;
X = c,
R = [d] ;
X = d,
R = [] ;
false.

接下来,使用member/2X-Y中的每个Y组成一对R

?- append(_,[X|R],[a,b,c,d]), member(Y,R), Pair=(X-Y).
X = a,
R = [b, c, d],
Y = b,
Pair = a-b ;
X = a,
R = [b, c, d],
Y = c,
Pair = a-c ;
X = a,
R = [b, c, d],
Y = d,
Pair = a-d ;
X = b,
R = [c, d],
Y = c,
Pair = b-c ;
X = b,
R = [c, d],
Y = d,
Pair = b-d ;
X = c,
R = [d],
Y = d,
Pair = c-d ;
false.

然后,使用findall/3收集列表中的所有对:

?- findall(X-Y, (append(_,[X|R],[a,b,c,d]), member(Y,R)), Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].

因此,您的最终解决方案可以表示为:

pairs(List, Pairs) :-
    findall(X-Y, (append(_,[X|R],List), member(Y,R)), Pairs).

一个使用示例是:

?- pairs([a,b,c,d], Pairs).
Pairs = [a-b, a-c, a-d, b-c, b-d, c-d].