多次删除重复

时间:2017-02-10 13:57:37

标签: prolog

我想从prolog中先前排序的列表中删除多个重复项。我希望输出看起来像这样:

示例1。

?- remove_dups ([1,1,2,2,3,4,5,5,6], List).
List = [3,4,6]

正如你所看到的,它不会删除相同元素的重复,而是全部删除。

我使用了以下算法,我做了一些修改但没有成功。 这是我使用的算法:

    remove_dups([], []).
    remove_dups([X], [X]).

    remove_dups([X,X|T], [X|R]) :-
        remove_dups([X|T], [X|R]).

    remove_dups([X,Y|T], [X|R]) :-
        X \== Y,
        remove_dups([Y|T], R).

    remove_dups([X,Y|T], [X|R]) :-
        (   X == Y
        ->  remove_dups([Y|T], [X|R])
        ;   remove_dups([Y|T], R)
        ).

然而,我对此算法的输出是这样的。

?- remove_dups([1,1,2,2,3,4,5,5,6], List).

List = [1,2,3,4,5,6]

但我希望它与示例1中的任何提示相同?

2 个答案:

答案 0 :(得分:3)

这与Include non-unique elements only非常相似,可以非常类似地解决。

我再次使用if_//3来保留关系的一般性:请注意,通常可以在多个方向中使用有用的Prolog谓词,因此像remove_dups/2这样的命令式名称不适合表达其他方向和更一般的用例。

相反,我将称之为 list_singulars/2 的关系,并将其定义为:

list_singulars(Ls0, Ls) :-
        phrase(list_singulars(Ls0, []), Ls).

list_singulars([], _) --> [].
list_singulars([L|Ls], Ls0) -->
        if_((memberd_t(L, Ls);memberd_t(L, Ls0)),
            [],
            [L]),
        list_singulars(Ls, [L|Ls0]).

这是一个简单的测试用例:

?- list_singulars([a,a,b], List).
List = [b].

你发布的例子:

?- list_singulars([1,1,2,2,3,4,5,5,6], List).
List = [3, 4, 6].

此外,我们还可以使用更多常规查询生成答案:

?- list_singulars([a,X], List).
X = a,
List = [] ;
List = [a, X],
dif(X, a).

请注意使用dif/2,这是一种真正的关系。有关详细信息,请参阅

以下是最常规查询:

?- list_singulars(Ls0, Ls).
Ls0 = Ls, Ls = [] ;
Ls0 = Ls, Ls = [_6826] ;
Ls0 = [_6826, _6826],
Ls = [] ;
Ls0 = [_6826, _6826, _6826],
Ls = [] ;
Ls0 = [_6826, _6826, _6826, _6826],
Ls = [] .

我们可以通过迭代加深轻松获得公平枚举

?- length(Ls0, _), list_singulars(Ls0, Ls).
Ls0 = Ls, Ls = [] ;
Ls0 = Ls, Ls = [_7798] ;
Ls0 = [_7798, _7798],
Ls = [] ;
Ls0 = Ls, Ls = [_8436, _8442],
dif(_8442, _8436) ;
Ls0 = [_7798, _7798, _7798],
Ls = [] ;
Ls0 = [_8494, _8494, _8506],
Ls = [_8506],
dif(_8506, _8494) .

答案 1 :(得分:0)

当您检测到重复项,即与[X,X|T]统一时,请从列表中删除剩余的X

remove_dups([], []).
remove_dups([X], [X]).
remove_dups([X,Y|T], [X|R]) :-
    X \= Y,
    remove_dups([Y|T], R).
remove_dups([X,X|T], R) :-
    skip(X, T, WithoutX),
    remove_dups(WithoutX, R).

正如您所看到的,您非常接近:remove_dups/2规则的第1,第2和第3条来自您的代码。唯一的区别在于最后一个子句,它在递归之前会跳过X的剩余值。

skip/2谓词可以按如下方式实现:

skip(_,[],[]).
skip(X, [X|T], T).
skip(X, [Y|T], [Y|T]) :- X \= Y.

Demo.