递归谓词输出列表差异(没有重复元素)

时间:2017-11-30 15:32:55

标签: prolog

我有下面的递归谓词来检查列表中的集合差异并输出这些。

我有这个工作,但也输出重复的值。 任何人都可以告诉我如何解决这个问题,以便输出没有重复的值。谢谢

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] ;

2 个答案:

答案 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两次。)