簡體   English   中英

如何在Prolog中確定給定列表中的所有對?

[英]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)而是尋找列表中XY之前的對。

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/2R每個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM