Prolog只删除唯一的元素

我想返回一个列表,例如删除所有独特的元素

remUniqueVals([1,1,2,2,3,4,4,5,6,6,6],Q). Q = [1,1,2,2,4,4,6,6,6]. 

我的问题是,目前我有代码返回

 remUniqueVals([1,1,2,2,3,4,4,5,6,6,6],Q). Q = [1, 2, 4, 6, 6]. 

这样只返回这些非唯一值的第一个实例。 这是我的代码:

 remUniqueVals([], []). remUniqueVals([Q1|RestQ],[Q1|Xs]) :- member(Q1,RestQ), remUniqueVals(RestQ,Xs). remUniqueVals([Q1|RestQ],Xs) :- remove(Q1,[Q1|RestQ], NewQ), remUniqueVals(NewQ,Xs). 

我可以看到member(Q1,RestQ)在第二次检查1,2,4时失败,因为他们现在不在列表中,因此将其删除。 我想要一些帮助解决这个问题,我的想法是检查member(Q1, PreviousQ) ,这是最后Q的元素。 不知道如何去执行,虽然任何帮助,将不胜感激。

更新:

好的,谢谢你们提出的build议,

 remUniqueVals(_,[], []). remUniqueVals(_,[Q1|RestQ],[Q1|Xs]) :- member(Q1,RestQ), remUniqueVals(Q1,RestQ,Xs). remUniqueVals(PrevQ,[Q1|RestQ],[Q1|Xs]) :- Q1 = PrevQ, remUniqueVals(PrevQ,RestQ,Xs). remUniqueVals(PrevQ,[_|RestQ],Xs) :- remUniqueVals(PrevQ,RestQ,Xs). remUniqueVals(0,[4,1,1,3,2,2,5,5],Q). Q = [1, 1, 2, 2, 5, 5]. remUniqueVals(0, [A,B,C], [1,1]). A = 1, B = 1, C = 1. 

这与原始解决scheme类似,但它将辅助列表中的非唯一值收集起来并进行检查,以避免从原始中删除最后一个:

 remove_uniq_vals(L, R) :- remove_uniq_vals(L, [], R). remove_uniq_vals([], _, []). remove_uniq_vals([X|T], A, R) :- ( member(X, A) -> R = [X|T1], A1 = A ; member(X, T) -> R = [X|T1], A1 = [X|A] ; R = T1, A1 = A ), remove_uniq_vals(T, A1, T1). 

testing…

 | ?- remove_uniq_vals([1,2,3,1,2,3,1,2,3,4,3], Q). Q = [1,2,3,1,2,3,1,2,3,3] (1 ms) yes | ?- remove_uniq_vals([1,1,2,2,3,4,4,5,6,6,6], Q). Q = [1,1,2,2,4,4,6,6,6] yes 

所以如果第一个参数是一个input,谓词就很好,并且它保持列表中其余元素的原始顺序。

然而,这个谓词并不完全是相关的 ,因为它将会失败一个情况,即第一个参数是一个已知数量的元素的未被证实的列表,而第二个参数是不同固定数量元素的列表。 所以这样的事情会起作用:

 | ?- remove_uniq_vals([A,B,C], L). B = A C = A L = [A,A,A] (1 ms) yes 

但是像下面这样的失败:

 | ?- remove_uniq_vals([A,B,C], [1,1]). no 

Prolog规则是彼此独立读取的,所以你需要一个规则来处理元素是唯一的,而不是一个规则。 如果元素的顺序不相关,则可以使用:

 ?- remUniqueVals([A,B,C], [1,1]). A = B, B = 1, dif(C, 1) ; A = C, C = 1, dif(B, 1), dif(B, 1) ; B = C, C = 1, dif(A, 1), dif(A, 1) ; false. ?- remUniqueVals([1,1,2,2,3,4,4,5,6,6,6],Q). Q = [1, 1, 2, 2, 4, 4, 6, 6, 6] ; false. remUniqueVals([], []). remUniqueVals([Q1|RestQ],[Q1|Xs0]) :- memberd(Q1, RestQ), phrase(delall(Q1, RestQ, NewQ), Xs0, Xs), remUniqueVals(NewQ, Xs). remUniqueVals([Q1|RestQ],Xs) :- maplist(dif(Q1), RestQ), remUniqueVals(RestQ,Xs). memberd(X, [X|_Xs]). memberd(X, [Y|Xs]) :- dif(X,Y), memberd(X, Xs). delall(_X, [], []) --> []. delall(X, [X|Xs], Ys) --> [X], delall(X, Xs, Ys). delall(X, [Y|Xs], [Y|Ys]) --> {dif(X,Y)}, delall(X, Xs, Ys). 

这里是memberd/2一个替代定义,使用if_/3可能更有效:

 memberd(E, [X|Xs]) :- if_(E = X, true, memberd(E, Xs) ). 

这是@ CapelliC解决scheme的另一个纯粹的关系解决scheme。 这一个现在保留重复的顺序。 有趣的是,如何在@ CapelliC的解决scheme中发生的隐式量化现在必须明确地进行。

拥有一个纯粹的关系定义的最大优点就是noes是noes。 而且是ayes。 那就是:你不必担心你所得到的答案是否正确。 这是正确的(或不正确的 – 但不是部分正确的)。 如果方法失败,则可以通过生成instantiation_error来清理非关系型解决scheme。 但是,如果你可以validation自己,那么他们都已经“忘记”了这些testing,从而为错误做好准备。 对这些其他解决scheme的安全testing可能已经被研究ground(Xs)ground(Xs), acyclic_term(Xs)但是经常被认为太受限制。

 remUniqueVals2(Xs, Ys) :- tfilter(list_withduplicate_truth(Xs),Xs,Ys). list_withduplicate_truth(L, E, Truth) :- phrase( ( all(dif(E)), ( {Truth = false} | [E], all(dif(E)), ( {Truth = false} | {Truth = true}, [E], ... ) ) ), L). all(_) --> []. all(P_1) --> [E], {call(P_1,E)}, all(P_1). ... --> [] | [_], ... . tfilter( _, [], []). tfilter(TFilter_2, [E|Es], Fs0) :- call(TFilter_2,E,Truth), ( Truth = false, Fs0 = Fs ; Truth = true, Fs0 = [E|Fs] ), tfilter(TFilter_2, Es, Fs). 

另一种更紧凑的方式使用if_/3

 tfilter( _, [], []). tfilter(TFilter_2, [E|Es], Fs0) :- if_(call(TFilter_2,E), Fs0 = [E|Fs], Fs0 = Fs ), tfilter(TFilter_2, Es, Fs). 

这是@ mbratch解决scheme的纯化版本。 它使用member/2的重新版本,这个member/2没有多余的答案member(X,[a,a])

 memberd_truth_dcg(X, Xs, Truth) :- phrase(( all(dif(X)), ( [X], {Truth = true}, ... | {Truth = false} ) ), Xs). 

一个稍微普遍的版本,只需要有一个列表前缀,而不是一个列表:

 memberd_truth(_X, [], false). memberd_truth(X, [X|_], true). memberd_truth(X, [Y|Ys], Truth) :- dif(X,Y), memberd_truth(X, Ys, Truth). 

variables的命名方式与@ mbratch解决scheme中的相同:

 remove_uniq_valsBR(L, R) :- remove_uniq_valsBR(L, [], R). remove_uniq_valsBR([], _, []). remove_uniq_valsBR([X|T], A, R) :- memberd_truth(X, A, MemT1), ( MemT1 = true, R = [X|T1], A1 = A ; MemT1 = false, memberd_truth(X, T, MemT2), ( MemT2 = true, R = [X|T1], A1 = [X|A] ; MemT2 = false, R = T1, A1 = A ) ), remove_uniq_valsBR(T, A1, T1). 

使用if/3更紧凑:

 remove_uniq_valsBR([], _, []). remove_uniq_valsBR([X|T], A, R) :- if_( memberd_truth(X, A), ( R = [X|T1], A1 = A ), if_( memberd_truth(X, T), ( R = [X|T1], A1 = [X|A] ), ( R = T1, A1 = A ) ) ) ), remove_uniq_valsBR(T, A1, T1). 

我不喜欢的是许多冗余的dif/2约束。 我希望这个版本会less一些:

 | ?- length(L,_),remove_uniq_valsBR(L,L). L = [] ? ; L = [_A,_A] ? ; L = [_A,_A,_A] ? ; L = [_A,_A,_A,_A] ? ; L = [_A,_A,_B,_B], dif(_B,_A) ? ; L = [_A,_B,_A,_B], dif(_A,_B), dif(_B,_A), dif(_B,_A), dif(_A,_B) ? ... 

当然可以检查一个dif/2是否已经存在,但是我更喜欢一个版本,在这个版本中,从一开始就有一个dif/2目标。

保留逻辑纯度 ! 基于if_/3(=)/3和元谓词 tpartition/4我们定义:

  remUniqueValues([],[])。
 remUniqueValues([X | Xs1],Ys1): - 
    t分区 ( = (X),Xs1,Eqs,Xs0),
    if_ ( Eqs = [],
        Ys1 = Ys0,
        append ([X | Eqs],Ys0,Ys1)),
    remUniqueValues(Xs0,Ys0)。

让我们看看它的行动!

 ? -  remUniqueValues([A,B,C],[1,1])。
        A = 1,B = 1,dif(C,1)
 ;  A = 1,dif(B,1),C = 1
 ;  dif(A,1),B = 1,C = 1
 ; 假。

 ? -  remUniqueValues([1,1,2,2,3,4,4,5,6,6,6],Vs)。
 Vs = [1,1,2,2,4,4,6,6,6]。  %确定性地成功

基于3个内置的解决scheme:

 remUniqueVals(Es, NUs) :- findall(E, (select(E, Es, R), memberchk(E, R)), NUs). 

可以看作是

find所有在列表中仍然出现在列表中的元素