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] 

どうすれば尻尾を取り除くことができますか?

ありがとう

4

5 に答える 5

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

非常に複雑な方法を使用して非常に単純なタスクを実行するため、修正するのは簡単ではありません。たとえば、memberを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].
于 2013-02-19T17:21:20.240 に答える
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).
于 2013-02-19T22:12:05.670 に答える
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).
于 2013-02-19T20:01:13.547 に答える
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] .
于 2013-02-21T18:48:46.540 に答える
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,[]).
于 2013-07-13T02:04:07.727 に答える