从Prolog中的列表中删除连续的重复项

时间:2016-07-01 09:24:54

标签: prolog

我有以下列表:

[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上检查了很多类似的问题。但在我的列表中,重复项是连续的,因此可能有更简单的解决方案。我找不到关于删除连续重复条目的问题。

4 个答案:

答案 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) .

请注意使用 以声明方式声明两个字词不同

顺便说一句,“正常”案例也有效:

?- 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).

这里an example using SWISh

答案 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.
 */