2013-02-19 22 views
0

我想從給定列表中刪除所有重複項。使用不需要的尾部刪除列表結果中的重複項

考慮下面的代碼:

% 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

從快速查看它必須是一個基本情況,如setify([],_)而不是setify([],[])。 – NotAUser 2013-02-19 16:48:37

+0

@NotAUser:不,不是。當我將它改爲'setify([],[])'時,它導致了一個無限循環。 – ron 2013-02-19 16:50:02

回答

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,[]). 
+0

這可以更有效地編碼。而Prolog帶着不記得的東西? – CapelliC 2013-07-13 06:44:40

4

您的問題(表面上)是成員/ 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]. 
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). 
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). 
+0

錯誤:source_sink'library(lambda)'不存在 – 2013-02-20 01:20:57

+0

lambda.pl可以在http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl找到,將其放入pl /圖書館。 – joel76 2013-02-20 07:38:52

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] .