我有以下列表:
[a,b,b,e,e,f,f,g]
第一个和最后一个条目是单个条目,而所有其他条目都是重复的。如何删除这些额外的条目。我不应该打扰订单。
我试过以下但是它得到一个空列表:
removeDups([], []).
removeDups([H1,H2|T], Newlist) :-
(H1 == H2 -> removeDups([H2|T],Newlist)
; removeDups(T,Newlist)).
?- removeDups([a,b,b,c,c,d,d,e],L).
L = [].
编辑:我已经在stackoverflow上检查了很多类似的问题。但在我的列表中,重复项是连续的,因此可能有更简单的解决方案。我找不到关于删除连续重复条目的问题。
答案 0 :(得分:4)
为什么要使用只能在非常特殊的情况下使用的解决方案,并在其他情况下产生错误的结果?命令式编程是如此1980年......我知道80年代很酷,但也有点限制,不是吗?
尝试考虑可以在所有方向使用的关系!
这是一个使用if_/3
来实现一般性的解决方案:
no_consecutive_duplicates([], []). no_consecutive_duplicates([L|Ls0], Ls) :- no_dups(Ls0, L, Ls). no_dups([], E, [E]). no_dups([L|Ls0], E, Ls) :- if_(L=E, Ls=Ls1, Ls=[E|Ls1]), no_dups(Ls0, L, Ls1).
它也适用于最常见的情况:
?- no_consecutive_duplicates(Ls0, Ls). Ls = Ls0, Ls0 = [] Ls = Ls0, Ls0 = [_G501] ; Ls = [_G501], Ls0 = [_G501, _G501] ; Ls = [_G501], Ls0 = [_G501, _G501, _G501] .
对于 fair 枚举,请使用例如:
?- length(Ls0, _), no_consecutive_duplicates(Ls0, Ls). Ls = Ls0, Ls0 = [] ; Ls = Ls0, Ls0 = [_G501] ; Ls = [_G501], Ls0 = [_G501, _G501] ; Ls = [_G775, _G775], Ls0 = [_G787, _G775], dif(_G775, _G787) .
请注意使用 prolog-dif 以声明方式声明两个字词不同。
顺便说一句,“正常”案例也有效:
?- no_consecutive_duplicates([a,b,c], Ls). Ls = [a,b,c]. ?- no_consecutive_duplicates([a,a,b,c,c], Ls). Ls = [a,b,c].
请注意,这两个查询都成功确定性。
我们可以对此进行概括并检查稍微复杂的情况并不是很好吗?
?- no_consecutive_duplicates([a,b,X], Ls). Ls = [a, b], X = b ; Ls = [a, b, X], dif(X, b).
留下纯粹的人!
答案 1 :(得分:1)
在谓词中,第二个参数应始终表示从第一个参数中删除重复项的结果。在分解为每种情况时,这导致以下条款:
remove_dups([], []). % Empty list is empty list with dups removed
remove_dups([X], [X]). % Single element list is itself with dups removed
% The result of removing duplicates from `[X,X|T]` should be the same
% as the result of removing duplicates from `[X|T]`
remove_dups([X,X|T], [X|R]) :-
remove_dups([X|T], [X|R]).
% The result of removing duplicates from `[X,Y|T]` where X and Y are different
% should be the result [X|R] where R is the result of removing duplicates
% from [Y|T]
remove_dups([X,Y|T], [X|R]) :-
X \== Y,
remove_dups([Y|T], R).
第3和第4条可以替换为:
remove_dups([X,Y|T], [X|R]) :-
( X == Y
-> remove_dups([Y|T], [X|R])
; remove_dups([Y|T], R)
).
但是它会限制第一个参数可变的解决方案。
答案 2 :(得分:1)
删除重复项的空列表当然仍然是一个空列表。
如果尾巴不是从头部开始,我们应该保持头部。重复数据删除的尾部是尾部,其副本被删除 这包括尾部为空的情况(因此它是单元素列表)。
如果列表确实重复开头,我们会保持头脑清醒。然后我们在删除其他副本时包含头部,因为头部可能会重复多次。如果我们不包括头部,我们就无法检查它的尾部。
remove_dups([],[]).
remove_dups([H|T], [H|T1]) :-
T \= [H|_],
remove_dups(T, T1).
remove_dups([H,H|T], L) :-
remove_dups([H|T], L).
答案 3 :(得分:0)
最简单的方法是使用Takeout函数和成员函数
takeout(X,[X|R],R).
takeout(X,[F|Fs],[F|S]):- takeout(X,Fs,S).
/*takeout function used to remove
delete given element from the list*/
rem([X],[X]).
rem([H|T],Z):- member(H,T) , takeout(H,[H|T],L) ,!, rem(L,Z).
rem([H|T],[H|Z]):- \+member(H,T) , rem(T,Z).
/* I used cut to stop backtracking of takeout function
rem([X],[X]). when only one elem present return the same list
rem([H|T],Z):-member(H,T) , takeout(H,[H|T],L) ,!, rem(L,Z).
used to takeout the duplicate element from the list.
rem([H|T],[H|Z]):- \+member(H,T) , rem(T,Z).
if Head is not present in the tail , do nothing and check for the same in tail.
*/