【发布时间】:2009-11-17 10:17:36
【问题描述】:
prolog中如何判断两个list是否有相同的元素? 如果我有两个列表 A 和 B,我想知道它们是否具有相同的元素。
【问题讨论】:
-
你能写一个欲望行为的例子吗?
-
编写一个 comp_list/2 当它们在列表中有相同元素时成功。
-
定义“相同”,即您的意思是 = 或 == 还是别的什么?
prolog中如何判断两个list是否有相同的元素? 如果我有两个列表 A 和 B,我想知道它们是否具有相同的元素。
【问题讨论】:
你需要写一个谓词。您可能会发现内置的 prolog member/2 很有用。
如果不给出答案,就很难再说下去了。想一想。你会明白的。
【讨论】:
使用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([],_,[]).
【讨论】:
dif/2 和(\+)/1 很可能不起作用:Y=a,doesIntersect([b,Y],[b]). 正确成功,但doesIntersect([b,Y],[b]),Y=a. 失败。所以你的程序不是关系。
我们从基于内置谓词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.
【讨论】:
您可以首先构建一个谓词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.
注意:无论元素的顺序或它们是否重复,此解决方案都有效。
【讨论】:
common_memberd([1],[X]), X=2. 成功,但 X=2, common_memberd([1],[X]). 失败。
common_memberd([X,Y, 1],[2,Z, 3]).
( ground(T+Q) -> true ; throw(error(instantiation_error,_)) ),或者使用@repeat的方法;或介于两者之间的使用 iso_dif/2 在术语实例化不充分的情况下也会产生 instantiation_error。
not/1不经常被支持,而是(\+)/1
如果这就是你要找的东西,请告诉我:
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.
【讨论】: