我想删除给定列表中的所有重复项。
请考虑以下代码:
% check if the given element is in the given list
member(Element,[Element|_]).
member(Element,[_|List]):-member(Element, List).
% append the element only if it's NOT already in the input list
appending([],X,X).
appending([H|T1],Elem,[H|T2]):- appending(T1,Elem,T2).
appendHlp(ListOrg,Res,Addme):- not(member(Addme,ListOrg)),
appending(ListOrg,[Addme],Res).
appendHlp(ListOrg,Res,Addme):- member(Addme,ListOrg),
Res=ListOrg.
% remove duplicates
setify([H|T],Set):-appendHlp(Set,Output,H),
setify(T,Output).
setify([],_).
当我运行代码时:
1 ?- setify([1,2,3,3,2],X).
输出结果为:
X = [1, 2, 3|_G2725]
如何删除尾巴?
谢谢
答案 0 :(得分:4)
您的问题(表面上看)是使用未实例化的变量调用member / 2,然后“构建”您在输出中看到的部分列表
[trace] ?- setify([1],X).
Call: (6) setify([1], _G340) ? creep
Call: (7) appendHlp(_G340, _G416, 1) ? creep
^ Call: (8) not(member(1, _G340)) ? creep
^ Fail: (8) not(user:member(1, _G340)) ? creep
Redo: (7) appendHlp(_G340, _G416, 1) ? creep
Call: (8) lists:member(1, _G340) ? creep
Exit: (8) lists:member(1, [1|_G409]) ? creep
Call: (8) _G418=[1|_G409] ? creep
Exit: (8) [1|_G409]=[1|_G409] ? creep
Exit: (7) appendHlp([1|_G409], [1|_G409], 1) ? creep
Call: (7) setify([], [1|_G409]) ? creep
Exit: (7) setify([], [1|_G409]) ? creep
Exit: (6) setify([1], [1|_G409]) ? creep
X = [1|_G409] .
要纠正起来并不容易,因为您使用非常错综复杂的方式来执行非常简单的任务。例如,如果您使用memberchk替换成员,或使用member(Addme,ListOrg)
替换[Addme]=ListOrg
,则您的程序将失败。
我建议采取Prolog社区接受的一些编程习惯。例如,尝试在输出之前放置输入参数。它并不总是可能的,因为Prolog是关系,但有助于编写更好的代码。
当然,sort / 2可以有效地产生输出而且没有麻烦。
编辑解决方案可以非常紧凑,基本的Prolog:
setify([E|R], U) :- memberchk(E, R), !, setify(R, U).
setify([E|R], [E|U]) :- setify(R, U).
setify([], []).
3 ?- setify([1,1,1,2,1,1],L).
L = [2, 1].
答案 1 :(得分:4)
如果你使用SWI-Prolog,你可以写
:- use_module(library(lambda)).
setify(L, Set) :-
foldl(\X^Y^Z^(memberchk(X, Y)->Z=Y; append(Y, [X], Z)), L, [], Set).
答案 2 :(得分:2)
正如CapelliC所说,你可以使用sort/2
- 它将删除重复项并对元素进行排序。集合通常以排序的形式表示。
如果你需要保留元素的原始顺序,这里不是非常有效但非常简单的实现:
setify([H|T], OldSet, NewSet) :-
( \+ memberchk(H, OldSet) ->
append(OldSet, [H], CurrentSet),
setify(T, CurrentSet, NewSet)
;
setify(T, OldSet, NewSet)
).
setify([], OldSet, OldSet).
setify(List, Set) :-
setify(List, [], Set).
答案 3 :(得分:1)
使用尾递归和单个谓词来完成整个事情的另一个解决方案,但不保留原始顺序。
% Finish recursing / empty list
remdup([], []).
% Recurse tail first, don't add H to the list if already included
remdup([H|T], NoDups) :-
remdup(T, NoDups),
member(H, NoDups).
% Second rule failed, so H must be unique - add to NoDups list
remdup([H|T], [H|NoDups]) :-
remdup(T, NoDups).
?- remdup([1,2,2,3,2,1,3,3,3,2],X).
X = [1, 3, 2] .
答案 4 :(得分:1)
我对Prolog很新。这是我想出的一个解决方案,用于删除重复的元素。希望这可以帮助。
% Define negation of "member"
notmember(X,L) :- not( member(X,L) ).
% Remove duplicates terminal case
removeDups( [], R, R).
% Case where the head element is a member of tail. Drop it.
removeDups( [H|T], R, A ) :- member(H,T) , removeDups( T, R, A ).
% Case where head element is unique
removeDups([H|T], R, A ) :- notmember(H,T), append(A,[H],N), removeDups(T,R,N).
% Main predicate to remove duplicates with original order maintained.
uniq(X,Y) :- removeDups(X,Y,[]).