MaXX99
MaXX99

Reputation: 59

Prolog remove multiple elements from a list

I know how to remove an element from a list but is there a way to remove more than one elements from a list? For example,

deletelist([a,b,c,a,b],[a,c],X)
X = [b,b] % delete a and c from the list.

Upvotes: 5

Views: 12021

Answers (5)

false
false

Reputation: 10102

Here is a definition that always produces correct answers (modulo termination):

deletelist(Xs, Ys, Zs) :-
   tfilter(not(list_memberd_truth(Ys)),Xs, Zs).

not(G, E, T) :-
   call(G, E, NT),
   ( NT = true, T = false
   ; NT = false, T = true
   ).

list_memberd_truth(Xs, X, Truth) :-
   memberd_truth(X, Xs, Truth).

Using tfilter/3 and memberd_truth/3 from other answers. In case your Prolog does not support dif/2, see iso_dif/2 for a safe approximation.

Some of the more unusual questions that still come out correct:

?- deletelist([a], [X], Zs).
   X = a, Zs = []
;  Zs = [a], dif(X, a)
;  false.
?- deletelist([X], [Y], [X]).
   dif(X, Y)
;  false.

And here some queries that actually should fail (and thus terminate) but rather loop. Note that looping is far better than giving an incorrect answer.

?- deletelist([a], Zs, Zs).
   error(resource_error(local_stack),_).

?- deletelist(Xs, Xs, Xs).
   Xs = []
;  error(resource_error(local_stack),_).

Upvotes: 1

Tom3993
Tom3993

Reputation: 33

deletelist(Xs,[],Xs).
deletelist(Xs,[Y|Ys],Zs):-
    delete(Xs,Y,As),
    deletelist(As,Ys,Zs).

To remove a single element in a list there is a library function 'delete/3' which take in a list and an item you want to remove from that list and returns the new list with the item removed. I have made use of this and recuresed overs the list of items that need removing from the list.

Upvotes: 0

Kaarel
Kaarel

Reputation: 10672

SWI-Prolog offers subtract/3:

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

?- listing(subtract).
lists:subtract([], _, []) :- !.
lists:subtract([A|C], B, D) :-
    memberchk(A, B), !,
    subtract(C, B, D).
lists:subtract([A|B], C, [A|D]) :-
    subtract(B, C, D).

Upvotes: 5

尾崎隆大
尾崎隆大

Reputation: 158


% sorry!

deletelist(Xs,Ys,Zs) :-
        findall(A,(
                    member(A,Xs),
                    \+(member(A,Ys))),
                Zs).

Upvotes: 0

pad
pad

Reputation: 41290

To remove multiple elements, we check whether an element is in the second list and remove it when the condition is true:

deletelist([], _, []).                  
deletelist([X|Xs], Y, Z) :- member(X, Y), deletelist(Xs, Y, Z), !.
deletelist([X|Xs], Y, [X|Zs]) :- deletelist(Xs, Y, Zs).

Upvotes: 3

Related Questions