如何确定两个列表在序言中是否具有相同的元素?如果我有两个列表 A 和 B,我想知道它们是否具有相同的元素。
5 回答
你需要写一个谓词。您可能会发现内置的 prologmember/2
很有用。
如果不给出答案,很难再说什么。想一想。你会明白的。
我们从基于内置谓词的纯实现开始member/2
:
common_member(Xs,Ys) :-
member(E,Xs),
member(E,Ys).
示例查询:
?- common_member([1,2,3],[1]).
true
; false.
?- common_member([1,2,3],[4]).
false.
?- common_member([1,2,3],[2,3,1]).
true
; true
; true
; false.
声明式地,上面的代码是可以的。但是,它在成功时会留下无用的选择点。此外,如果两个列表中存在多个项目,我们会得到多余的答案。
我们能否在保持逻辑纯洁的同时提高上述效率方面? 是的!
但是怎么做?通过if_/3
与具体化的测试谓词一起使用memberd_t/3
!
common_memberd([X|Xs],Ys) :-
if_(memberd_t(X,Ys), true, common_memberd(Xs,Ys)).
让我们再次运行上面的示例查询,这次是common_memberd/2
:
?- common_memberd([1,2,3],[1]).
true.
?- common_memberd([1,2,3],[4]).
false.
?- common_memberd([1,2,3],[2,3,1]).
true.
冗余答案已被消除,随后的查询确定性地这样做。
请注意,这common_memberd/2
是纯粹的,因此即使对于非常一般的查询,我们也会得到正确的答案!
?- common_memberd([1,2,3],[A,B]).
A=1
; dif(A,1), B=1
; A=2 , dif(B,1)
; dif(A,1), dif(A,2), B=2
; A=3 , dif(B,1), dif(B,2)
; dif(A,1), dif(A,2), dif(A,3), B=3
; false.
怎么用intersection/3
?
doesIntersect(X,Y) :-
intersection(X,Y,Z),
dif(Z,[]).
如果intersection/3
产生一个空列表,那么这些列表没有共同点,结果为假。
intersection/3
member/2
递归调用:
intersection([X|Tail],Y,[X|Z]) :-
member(X,Y),
intersection(Tail,Y,Z).
intersection([X|Tail],Y,Z) :-
\+ member(X,Y),
intersection(Tail,Y,Z).
intersection([],_,[]).
您可以首先构建一个谓词differs/2
来验证列表中的任何元素A
是否不是列表的成员B
。如果你能找到A
满足这个条件的元素,那么你就可以肯定它A
不包含在B
. 这实际上更容易尝试验证 的每个元素A
是否存在于B
.
使用内置谓词member/2
,differs/2
将如下所示:
differs(T, Q):-
member(X,T),
not( member(X, Q)).
现在要证明两个列表都包含相同的元素,您只需要验证它们不包含differs
。使用 @repeat 使用的相同谓词名称(好奇,现在谁在重复?),这是我的common_memberd\2
谓词:
common_memberd(T, Q):-
not( differs(T, Q)),
not( differs(Q, T)).
咨询:
?- common_memberd( [2,3,4,1], [3, 1,4,2]).
true.
?- common_memberd( [2,3,1,5], [3, 1,4,2]).
false.
注意:无论元素的顺序或它们是否重复,此解决方案都有效。
让我知道这是否是您要寻找的东西:
same(T, Q) :- any(T, Q), !; any(Q, T), !.
any([X|_], [X,_]):- !.
any([X|T], Q) :- member(X, Q), !; any(T, Q), !.
如果您咨询它:
?- same([1,2,3,4], [3]).
true.
?- same([1,2,3,4], [4]).
true.
?- same([1], [1,4]).
true.
?- same([1,4], [1]).
true.