プロローグでリスト要素の連続した重複を排除する

Nov 27 2020

元々の問題は、以下を取得する方法を考え出すことでした

remove([a,a,a,b,q,q,q,q,e,e,e]),X)
X = [a,b,q,e]

回答

1 rajashekar Nov 28 2020 at 05:20

この問題は、リストに沿って1回繰り返すことで解決できます。リストの任意の時点で、現在の要素と次の要素をチェックします。それらが同じである場合は現在の要素を無視し、異なる場合は現在の要素を取得します。

rm_dup([], []).
rm_dup([X], [X]).
rm_dup([X1, X2 | Xs], [X1 | Ys]) :-
    dif(X1, X2), rm_dup([X2|Xs], Ys).
rm_dup([X, X | Xs], Ys) :-
    rm_dup([X | Xs], Ys).

1番目と2番目の句は、重複する要素がない基本句です。3番目と4番目の句は再帰的なルールです。

3番目の節では、入力リストに2つの値がX1ありX2、それらが異なるdif(X1, X2)場合は、現在の値を保持することを示します。

4番目の節では、同じ連続する値がある場合、現在の値を無視します。

3番目と4番目の句は相互に排他的であるため、述語を決定論的にするには、次のように組み合わせる方がよいでしょう。

rm_dup([X], [X]) :- !.
rm_dup([X1, X2 | Xs], Ys) :-
    dif(X1, X2) -> (rm_dup([X2 | Xs], Ys1), Ys = [X1 | Ys1]);
    rm_dup([X2 | Xs], Ys).

さらに良いのは、条件として等式を使用し、then句とelse句を反転することです

rm_dup([X], [X]) :- !.
rm_dup([X1, X2 | Xs], Ys) :-
    X1 = X2 ->  rm_dup([X2 | Xs], Ys);
    rm_dup([X2 | Xs], Ys1), Ys = [X1 | Ys1].
a3yko Nov 28 2020 at 03:41

ちょっと長いですが、これで解決しました。

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

remove([],[]).
remove([H|T], [H|R]) :- 
    member(H,T),!,
    delete(H,T,R1),
    remove(R1,R).

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