Remove both the value and all duplicates of that value in a list in prolog

给你一囗甜甜゛ 提交于 2019-12-23 15:33:33

问题


I'm having some trouble removing values from a list in prolog. I have a list of colors and I want to add a list of colors to it and keep all the values that have no duplicate and remove the rest.

[green, red, blue, purple, yellow, brown, orange, black, purple]

so purple appears twice in this list and I want to remove both of them. This is the list I want to be returned.

[green, red, blue, yellow, brown, orange, black]

I currently have this to remove all the duplicates but I can't get both purples out.

mymember(X,[H|_]) :- X==H,!.
mymember(X,[_|T]) :- mymember(X,T).

not(A) :- \+ call(A).

set([],[]).
set([Head|Tail],[Head|Out]) :-
    not(mymember(Head,Tail)),
    set(Tail, Out).
set([Head|Tail],Out) :-
    mymember(Head,Tail),
    set(Tail, Out).

this is the result I get now:

[green, red, blue, yellow, brown, orange, black, purple]

回答1:


The simple way...a one-liner:

singletons(Xs,Zs) :-
  findall( X , ( append(P,[X|S],Xs), \+member(X,P), \+member(X,S) ) , Zs )
  .



回答2:


Stay pure by using tfilter/3 in combination with list_uniqmember_t/3!

list_uniqs(Es, Us) :-
   tfilter(list_uniqmember_t(Es), Es, Us).

The sample query given by the OP has the expected result:

?- list_uniqs([green,red,blue,purple,yellow,brown,orange,black,purple], Xs).
Xs = [green,red,blue,yellow,brown,orange,black]. % succeeds deterministically

Do we get logically sound answers for more general queries, too?

?- list_uniqs([A,B,A], []).
   A=B
;  false.

?- list_uniqs([A,B,A], [_]).
dif(A,B).

?- list_uniqs([A,B,A], [_,_]).
false.

?- list_uniqs([A,B,A], Xs).
   Xs = [] ,     A=B
;  Xs = [B], dif(A,B).

Yes! How about something a little more general?

?- list_uniqs([A,B,C],Xs).
   Xs = []     ,     A=B           ,     B=C
;  Xs = [C]    ,     A=B           , dif(B,C)
;  Xs = [B]    ,               A=C , dif(B,C)
;  Xs = [A]    ,           dif(A,C),     B=C 
;  Xs = [A,B,C], dif(A,B), dif(A,C), dif(B,C).

It works!




回答3:


I think you're on the right track. Here's an approach using the -> ; construct and taking advantage of the delete/3 predicate, which removes ALL duplicates:

remdup([], _, []).
remdup([H|T], X, R) :-
    (   H == X
    ->  (   member(X, T)
        ->  delete(T, X, R)     % only delete if it's in the list more than once
        ;   R = [H|R1],
            remdup(T, X, R1)
        )
    ;   R = [H|R1],
        remdup(T, X, R1)
    ).

Another solution, using select/3 as well as delete/3:

remdup(L, X, R) :-
    (select(X, L, L1), select(X, L1, L2))
->  delete(L2, X, R)
;   L = R.

select/3 extracts one instance of an element from a list. If it cannot find the element, it fails. So in the above, we delete all the instances if we're able to find at least two of them.


A solution which does the whole list (minus the middle argument that specifies the single item to remove):
remdup([], []).
remdup([H|T], R) :-
    (   select(H, T, T1)
    ->  delete(T1, H, R1),
        remdup(R1, R)
    ;   R = [H|R1],
        remdup(T, R1)
    ).



回答4:


I fixed it by doing this:

my_delete(Res, [], Res).
my_delete(Colorslist, [Head|Tail], R) :-  
    my_delete_worker(Colorslist, Head, Result), 
    my_delete(Result, Tail, R).

my_delete_worker([], _, []).
my_delete_worker([X|T], X, R) :-
    my_delete_worker(T, X, R).
my_delete_worker([H|T], X, [H|R]) :-
    X \= H,
    my_delete_worker(T, X, R).

I forgot to put the result of the first color into the colorslist for the second color. When it arrives at the base case I unify my colorslist with the result. Thanks for your help lurker!




回答5:


simpler (and impure :-)

singletons(Xs, Zs) :- findall(X, (select(X,Xs,Ys), \+memberchk(X,Ys)), Zs).


来源:https://stackoverflow.com/questions/33259691/remove-both-the-value-and-all-duplicates-of-that-value-in-a-list-in-prolog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!