我有下面的递归谓词来检查列表中的集合差异并输出这些。
我有这个工作,但也输出重复的值。 任何人都可以告诉我如何解决这个问题,以便输出没有重复的值。谢谢
setDiff([],Y,[]).
setDiff([X|R],Y,Z) :- member(X,Y), setDiff(R,Y,Z).
setDiff([X|R],Y,[X|Z]) :- \+(member(X,Y)), setDiff(R,Y,Z).
预期输出
?- setDiff([1,2,3,3,a], [b,d,2], X).
X = [a, 3, 1] ;
实际输出
?- setDiff([1,2,3,3,a], [b,d,2], X).
X = [a, 3, 3, 1] ;
答案 0 :(得分:1)
一个简单的解决方案是在规则3中添加一个条件,如果[X|Z]
已经X
已经在Z
中,则将第三个参数与Z
统一起来,并将其与{统一{1}}如果X
中已有Z
:
setDiff([],_,[]).
setDiff([X|R],Y,Z) :- member(X,Y), setDiff(R,Y,Z).
setDiff([X|R],Y,L) :-
\+ member(X,Y),
setDiff(R,Y,Z),
( member(X, Z) ->
L = Z
; L = [X|Z]
).
注意:我在第一条规则中将Y
替换为_
,以避免使用"单例变量"警告:在这种情况下确实没有必要命名Y,因为它从未在规则中使用过。此警告可帮助您检测命名变量仅使用一次(从未使用过)的可能错误。
答案 1 :(得分:0)
如果要保持尾递归(效率更高),可以使用两个参数作为输出列表:
setDiff(Xs,Ys,Zs) :-
setDiff(Xs,Ys,[],RevZs), reverse(RevZs,Zs).
setDiff([X|Xs],Ys,Zs0,Zs) :-
( ( member(X,Ys) ; member(X,Zs0) ) ->
Zs1 = Zs0
; Zs1 = [X|Zs0] ),
setDiff(Xs,Ys,Zs1,Zs).
setDiff([],_,Zs,Zs).
(这也避免了使用相同的参数调用member/2
两次。)