web-dev-qa-db-ja.com

SWI-Prologのリストから重複を削除する方法は?

したがって、指定されたリストから重複する要素を削除する述語_remove_duplicates/2_を記述する必要があります。例えば:

?- remove_duplicates([a,a,b,c,c], List). List = [a,b,c] Yes

私はSWI-Prologを2日間しか学習しておらず、Prologの基本のみを理解していることを覚えておいてください。これは私が現在持っているものです:

remove_duplicates([H | T], List) :- member(H, T), append(T, [], List1).

これはリスト_[a,a,b,c]_では機能しますが、テールの2つの要素が同じであるリストでは機能しません。どういうわけか私は一時的なリストにヘッドを削除し、新しいヘッドを作成し、述語を繰り返す必要があると考えました。どうすればいいのか分かりません。また、たとえば_[a,b,b,c,]_のようなリストのように、ヘッドがテールにない場合、member(H, T)がtrueではないため、ターミナルはFalseとだけ表示します。

何か案は?

8
Marthijn

重複を削除するには、順序が重要ではない場合、最も簡単なのはsort/2

?- sort([a,a,b,b,c], X).
X = [a, b, c].

?- sort([c,c,a,a,b], X).
X = [a, b, c].

もちろん、要素の元の順序が失われていることがわかります。さらに重要なのは、これは、並べ替えるリストが既に固定されている(自由変数がない)場合にのみ正しいことを保証するだけです。この小さな例を考えてみましょう:

?- sort([X,Y], [a,a]).
X = Y, Y = a.

あなたの目標が重複を削除することである場合、正確に正しく感じていません...

だからあなたも書いたかもしれません:

must_be(ground, List), sort(List, Unique).

自分で行うこともでき、元の順序を維持できます。しかし、その場合は、これまでに見た要素を記録しておく必要があります。たとえば、追加のリストにそれらを保持できます。

これまでに見た要素のリストは最初は空です

list_unique(List, Unique) :-
    list_unique_1(List, [], Us).

list_unique_1([], _, []).
list_unique_1([X|Xs], So_far, Us) :-
    list_unique_2(X, Xs, So_far, Us).

これまでに見たすべての要素がXと異なる場合は、それを一意の要素のリストに入れて、これまでに見た要素のリストに追加します。

list_unique_2(X, Xs, So_far, [X|Us]) :-
    maplist(dif(X), So_far),
    list_unique_1(Xs, [X|So_far], Us).

これまでに要素が表示されている場合は、スキップしてください。

list_unique_2(X, Xs, So_far, Us) :-
    memberchk(X, So_far),
    list_unique_1(Xs, So_far, Us).

これは、最も簡単な方法です。より複雑になる可能性のある他の賢明な方法がありますが、これが最も簡単に記述できます。

9
user1812457

述語に関するいくつかの問題があります。

remove_duplicates([H | T], List) :-
  member(H, T),
  append(T, [], List1).

まず、再帰的な述語が必要です。リストの先頭を確認しますが、リストの末尾を再帰的に確認しません。

したがって、次のように変更できます。

remove_duplicates([H | T], List) :- 
      member(H, T),
      remove_duplicates( T, List).

上記は再帰的に尾を呼び出します。

次に、hがリストのメンバーでない場合にどうなるかを決定する必要があるため、別の句を追加する必要があります。

remove_duplicates([H | T], [H|T1]) :- 
       \+member(H, T), 
       remove_duplicates( T, T1).

上記は、HがTに存在するかどうかを確認し、存在しない場合は、リストの最初の要素を要素Hに強制します。

これがあまり明確でない場合、上記はこれと同じです。

  remove_duplicates([H | T], List) :- 
           \+member(H, T), 
           List=[Head|Tail],
           Head=H,
           remove_duplicates( T, Tail).

これはあまりエレガントではありません。前の仕組みを理解するためです。

最後に、空のリストの再帰のベースが必要です。

remove_duplicates([],[]).

したがって、上記の句による述語remove_duplicatesは次のようになります。

remove_duplicates([],[]).

remove_duplicates([H | T], List) :-    
     member(H, T),
     remove_duplicates( T, List).

remove_duplicates([H | T], [H|T1]) :- 
      \+member(H, T),
      remove_duplicates( T, T1).

ただし、上記の例では要素ごとに1回しか保持されないことに注意する必要があります。

remove_duplicates([a,a,b,c],L).
L = [a, b, c] ;
false.

これは問題ありませんが、以下の例を確認してください。

remove_duplicates([a,a,b,a,c],L).
L = [b, a, c] ;
L = [b, a, c] ;
false.

これはL = [b、a、c]を返します。これは、リストの最初の2つの「a」を消去し、3番目のみを保持したためです。

重複のみを消去したい場合は、メンバー述語のため、上記は機能しません。あなたは書くことができます:

remove_duplicates2([],[]).

remove_duplicates2([H],[H]).

remove_duplicates2([H ,H| T], List) :-remove_duplicates( [H|T], List).

remove_duplicates2([H,Y | T], [H|T1]):- Y \= H,remove_duplicates( [Y|T], T1).

述語remove_duplicates2はremove_duplicatesに似ていますが、いくつかの重要な違いがあります:

1)メンバーを使用しませんが、2つのSAME要素を持つリスト[H、H | T]があり、1つだけを保持する場合に何が起こるかを調べます。そのため、最初のHを無視して、recursively remove_duplicates2([H | T]、L)。

2)[H、Y | T](少なくとも2つの要素H、Yとリストの末尾を含むリスト)を入力し、H\= Yの場合、remove_duplicates2([Y | T]、T1)を呼び出し、戻りたいリストにHを格納しました。

3)最後に、すべての句には少なくとも2つの要素が必要であるため、再帰のベースは1つの要素を持つリストです:remove_duplicates2([H]、[H])。

4)句remove_duplicates2([]、[])。入力が空のリストの場合にのみ使用されるため、この入力をカバーする必要があります。

Remove_duplicates2述語はあなたに与えるでしょう:

 remove_duplicates2([a,a,b,a,c],L).
L = [a, b, a, c] ;
false.

remove_duplicates2([a,a,b,c],L).
L = [a, b, c] ;
false.
3
coder

これを試してください、それがあなたを助けることを願っています:

delete3(_,[],[]).
delete3(X,[X|T],R):- delete3(X,T,R).
delete3(X,[H|T],[H|R]) :- delete3(X,T,R).

remove_duplicates([],[]).
remove_duplicates([H|T], [H|R]) :- 
    member(H,T),!,
    delete3(H,T,R1),
    remove_duplicates(R1,R).

remove_duplicates([H|T],[H|R]):-
    remove_duplicates(T,R).

2番目の述語では、ヘッド変数*(H)*がリスト*(T)*の末尾のメンバーであるかどうかを確認します。そうである場合、最初の述語を呼び出して、末尾にあるヘッド変数と等しいすべての変数を削除します。

0
Sara Popa
% remdup(List, List_No_duplicates).
remdup([],[]).
remdup([H|T],Lnd):- rd1(H,T,T1), remdup(T1,Tnd),Lnd=[H|Tnd].
% rd1(X,L,Lr) removes all occurance of X in List L and store result in List Lr
rd1(_,[],[]).    
rd1(X,[X|T],Lx):-    rd1(X,T,Lx).
rd1(X,[Y|T],Lx):-    rd1(X,T,Lx1),Lx=[Y|Lx1].

仕組み-述語remdup

  1. 指定されたリストの最初の要素Hを取得し、テールパーツT内のそのすべての出現を削除します-この結果をリストT1に格納します。そして

  2. T1ストアの結果でremdupを再帰的に呼び出してTndに格納します。そして

  3. 要素HをTndに追加します。Tndは、実際にはremdupの再帰呼び出しによって変更されたテールパーツTであり、すでにすべての重複がなく、Hの出現は含まれていません。

述語-rd1

  1. 空白のリストからすべての出現と何かを削除すると、空白のリストになります
  2. 頭がXと一致する場合-テールパーツで再び呼び出しを続けます
  3. 頭がXと一致しない場合-尾部に進みます。そして、変更されたテールパーツに一致しないヘッドYを追加します。これにより、Xのすべての出現がなくなります。
0

list_to_set/2 またはsort/2ここでの回答で述べたように。

0
Anton Danilov