当给定一个列表时,我想计算列表中所有可能的对组合。
例如 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)
当给定一个列表时,我想计算列表中所有可能的对组合。
例如 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)
使用select/3
两次(或select/3
一次member/2
又一次)将使您在这里实现您想要的。我会让你弄清楚细节,如果仍然麻烦,我会寻求帮助。
顺便说一句,列表的 Prolog 语法不是(a, b, c)
但是[a, b, c]
(好吧,它是语法糖,但我会留在那里)。
编辑:正如@WillNess 指出的那样,您不是在寻找任何对(X, Y)
,而只是在寻找列表X
中之前Y
的对。
DCG 非常适合:正如@false 所描述的,它们可以产生一个图形吸引人的解决方案:
... --> [] | [_], ... .
pair(L, X-Y) :-
phrase((..., [X], ..., [Y], ...), L).
或者,如果您使用 SWI-Prolog,也可以调用 toappend/2
以类似的方式来解决问题,但效率低于 DCG:
pair2(L, X-Y) :-
append([_, [X], _, [Y], _], L).
正如@WillNess 在他的评论中所建议的那样,您可以通过基本递归来做到这一点。如果需要,我将把这部分留给他详细说明!
好的,所以翻译 Haskell 定义
pairs (x:xs) = [ (x,y) | y <- xs ]
++ pairs xs
pairs [] = []
(这意味着,列表中带有 headx
和 tail的对是 inxs
的所有对(x,y)
,y
也是 inxs
的对xs
;并且在空列表中没有对)
作为回溯Prolog 谓词,在每次重做时一一生成对,这是对上述内容的直接一对一重写,
pair( [X|XS], X-Y) :- member( ... , XS) % fill in
; pair( XS, ... ). % the blanks
%% pair( [], _) :- false.
要获得所有可能的对,请使用findall
:
pairs( L, PS) :- findall( P, pair( L, P), PS).
bagof
如果您的列表中可以包含逻辑变量,请考虑使用。不过,控制bagof
的回溯可能是一个复杂的问题。
pairs
也可以写成(几乎)确定性、非回溯、递归定义,通过累加器参数构造其输出列表,就像函数式编程语言一样——这里是自上而下的方式,这就是 Prolog 擅长的地方:
pairs( [X|T], PS) :- T = [_|_], pairs( X, T, T, PS, []).
pairs( [_], []).
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).
您可以使用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/2
形成一对X-Y
,对于每个Y
in 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].
这是解决此问题的一种可能方法。
如果第三个参数对应于包含对的列表,则以下谓词combine/3
为真,其中每对的第一个元素等于 的第一个参数combine/3
。每对的第二个元素将对应于 predicate 的第二个参数中的列表项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)].