我想返回一个删除所有唯一元素的列表,例如
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
中已有的元素。不知道如何实施,虽然任何帮助将不胜感激。
更新
好的,谢谢你最后提出的建议:
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.
答案 0 :(得分:6)
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) ).
答案 1 :(得分:5)
这与原始解决方案类似,但它会收集辅助列表中的非唯一值并检查它以避免从原始列表中删除最后一个:
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).
...测试
| ?- 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
因此,如果第一个参数是输入,谓词的效果很好,并且它保持列表中其余元素的原始顺序。
但是,这个谓词并不完全是 relational ,因为它会使第一个参数是已知数量的元素的未实例化列表而第二个参数是不同列表的情况失败固定数量的元素。所以这样的事情会起作用:
| ?- 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
答案 2 :(得分:5)
这是另一个纯粹的关系解决方案,受@ CapelliC解决方案的启发。现在这个保留了重复的顺序。有趣的是,现在必须明确地完成@CapelliC解决方案中隐式量化的发生。
拥有纯粹的关系定义的最大优点是noes is noes。并且ayes是ayes。那就是:你不必担心你得到的答案是否正确。这是正确的(或不正确 - 但它不是部分正确)。如果方法失败,通常可以通过生成instantiation_error
来清除非关系解决方案。但是你可以自己验证,两者都“忘记”了这样的测试,从而为bug做好了准备。对其他解决方案的安全测试可能是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).
答案 3 :(得分:3)
这是@ mbratch解决方案的纯化版本。它使用了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).
变量的命名方式与@ mbratch的解决方案相同:
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
约束。我希望这个版本的版本更少:
| ?- 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
目标较少的版本。
答案 4 :(得分:3)
保留logical-purity!基于if_/3
,(=)/3
和meta-predicate tpartition/4
我们定义:
remUniqueValues([], []). remUniqueValues([X|Xs1], Ys1) :- tpartition(=(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 ; false. ?- remUniqueValues([1,1,2,2,3,4,4,5,6,6,6], Vs). Vs = [1,1,2,2,4,4,6,6,6]. % succeeds deterministically
答案 5 :(得分:2)
基于3个内置的解决方案:
remUniqueVals(Es, NUs) :-
findall(E, (select(E, Es, R), memberchk(E, R)), NUs).
可以读作
找到选中后仍然出现在列表中的所有元素