List 仅删除唯一元素
有很多关于如何删除重复项和类似问题的资源,但我似乎找不到任何关于删除唯一元素的资源。我正在使用SWI Prolog,但我不想使用内置程序来实现这一点 也就是说,调用List 仅删除唯一元素,list,prolog,prolog-dif,List,Prolog,Prolog Dif,有很多关于如何删除重复项和类似问题的资源,但我似乎找不到任何关于删除唯一元素的资源。我正在使用SWI Prolog,但我不想使用内置程序来实现这一点 也就是说,调用remove\u unique([1,2,2,3,4,5,7,6,7],X)。应该会很高兴地得到X=[2,2,7,7] 显而易见的解决办法是按照 count(_, [], 0) :- !. count(E, [E | Es], A) :- S is A + 1, count(E, Es, S). count(E, [_ | E
remove\u unique([1,2,2,3,4,5,7,6,7],X)。
应该会很高兴地得到X=[2,2,7,7]
显而易见的解决办法是按照
count(_, [], 0) :- !.
count(E, [E | Es], A) :-
S is A + 1,
count(E, Es, S).
count(E, [_ | Es], A) :-
count(E, Es, A).
is_unique(E, Xs) :-
count(E, Xs, 1).
remove_unique(L, R) :- remove_unique(L, L, R).
remove_unique([], _, []) :- !.
remove_unique([X | Xs], O, R) :-
is_unique(X, O), !,
remove_unique(Xs, O, R).
remove_unique([X | Xs], O, [X | R]) :-
remove_unique(Xs, O, R).
很快就会明白为什么这不是一个理想的解决方案:count
是O(n)
,是唯一的,因为它只使用count
。我可以通过fail
ing改进这一点,当我们找到多个元素时,但最坏的情况仍然是O(n)
然后我们来到删除\u unique
。对于每个元素,我们检查当前元素在O
中是否唯一。如果测试失败,元素将添加到下一个分支中的结果列表中。在O(n²)
中运行,我们得到了很多推论。虽然我不认为我们能在最坏的情况下加快速度,但我们能做得比这个天真的解决方案更好吗?我能清楚地看到的唯一改进是将count
更改为在识别出>1个元素后立即失败的内容。只要您不知道列表是以任何方式排序的,并且您希望保留非唯一元素的顺序,在我看来,您似乎无法避免进行两次传递:第一次计数出现,然后只拾取重复的元素
如果在第二次过程中使用(自平衡?)二叉树进行计数和查找,会怎么样?绝对不是O(n²),至少…与
并且,我们定义remove_unique/2
如下:
remove_unique([], []).
remove_unique([E|Xs0], Ys0) :-
tpartition(=(E), Xs0, Es, Xs),
if_(Es = [], Ys0 = Ys, append([E|Es], Ys, Ys0)),
remove_unique(Xs, Ys).
您可以先排序(O(N*log(N)),然后删除唯一的元素(O(N)),然后对每个元素使用二进制搜索或堆来确定它是否唯一O(N*log(N)),这是一个很好的建议,+1!还可以查看Ulrich Neumerkel的美丽版本list_to_set/2
,使用排序和统一有效地检测重复元素:。
?- remove_unique([1,2,2,3,4,5,7,6,7], Xs).
Xs = [2,2,7,7]. % succeeds deterministically