[英]How to predicate all pairs in a given list in Prolog?
當給定一個列表時,我想計算列表中所有對的可能組合。
例如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,則對append/2
的調用也可以達到這種效果,但方式卻比DCG效率低:
pair2(L, X-Y) :-
append([_, [X], _, [Y], _], L).
您可以按照@WillNess在他的評論中建議的基本遞歸進行操作。 如有需要,我將留給他詳細介紹!
好,所以翻譯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
也可以寫為確定性,非回溯,遞歸定義,通過累加器參數構造其輸出列表-在這里以自上而下的方式進行,這實際上使它成為差異列表 :
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).
這是解決此問題的一種可能方法。
如果第三個參數對應於包含對的列表,則以下謂詞combine/3
為true,其中每對的第一個元素等於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)].
您可以使用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
為R
每個Y
形成一對XY
:
?- 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].
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.