Alvi
Alvi

Reputation: 767

How to remove a list from a list in prolog?

I want to implement the following problem in prolog:
Given L1=[1,2,3,4] and L2=[2,3,4]
calling a function named remove_list(L1,L2,L) will remove L2 from L1 .
So L will be [1]. But if the elements of the 2nd list are not in the same order as in L1 or more accurately the 2nd one is not a subset of the first List ,it wont remove anything.
SayL1=[1,2,3,4,5] and L2=[2,3,6] or L2=[2,6] or L2=[4,3,2] will result L=[1,2,3,4,5]
Any help will be highly appreciated. Thanks in advance

Upvotes: 6

Views: 9665

Answers (3)

ibda
ibda

Reputation: 498

In general, if you just want to delete multiple elements in a list from another list you can just use:

subtract(+Set, +Delete, -Result)

where set = unorderd list which can have some duplicated elements and delete = list of element we want to delete from Set.

Ex:

subtract([1,3,5,6,4,2,3], [1,2,3], R).
R = [5, 6, 4].

Upvotes: 1

Yasel
Yasel

Reputation: 3120

You can build your predicate remove_list/3 using recursivity, which is an useful tool when dealing with lists in Prolog.

remove_list([], _, []).
remove_list([X|Tail], L2, Result):- member(X, L2), !, remove_list(Tail, L2, Result). 
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).

Consult:

?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].

The idea is to copy every element in your original list "L1" to your final list "L", except when that element is member of the second list "L2".
Your base clause is your stop condition, when your original list "L1" is empty, in that case ignoring your list "L2", the result is always the same empty list. (You can't delete nothing from the empty list).
Your second clause, don't copy the element in the head of the list "L1" to the final list "L" if that element in the head is member of the list "L2", also make the recursive call to the predicate with the Tail of your list "L".
And the final clause, copy the element in the head of the list "L1" to the final list "L", and also make the recursive call to the predicate with the Tail of that list "L". We don't need the goal member/2 here, because we used a cut in the previous clause.

EDIT: This answer should only be considered if you want to remove items from the list "L1" contained in the "L2" list, regardless of the order. To remove the subset "L2" from set "L1", please use Lurker's solution or this other solution:

remove_list(L, [], L):- !.
remove_list([X|Tail], [X|Rest], Result):- !, remove_list(Tail, Rest, Result).
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).

This new solution considers the order of the elements in list "L2", but not in the strict sense, ie, may be interspersed in the original list "L1", which does not violate the concept of "L2" being a subset of "L1".

[2,4] is a subset of the set [1,2,3,4,5,6], but [2,4,7] is not:

?- remove_list([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].

?- remove_list([1,2,3,4,5,6], [4,2], L).
false.

?- remove_list([1,2,3,4,5,6], [2,4,7], L).
false.

Now, given the fact that is desired to obtain the original set rather than the negative response in case that any of the elements from the original set can be removed, then we use an auxiliary predicate:

rm_subset(L1, L2, L):-  remove_list(L1, L2, L),!.
rm_subset(L1, L2, L1).

Consult:

?- rm_subset([1,2,3,4,5,6], [4,2], L).
L = [1, 2, 3, 4, 5, 6].

?- rm_subset([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].

Upvotes: 8

lurker
lurker

Reputation: 58244

Another possible solution, using the delete/3 predicate:

remove_elements(L, [H|T], R) :-
    delete(L, H, R1),
    remove_elements(R1, T, R).
remove_elements(L, [], L).

| ?- remove_elements([4,5,1,6,3], [1,4,7], L).

L = [5,6,3] ? ;

no
| ?-


EDIT I just realized I completely misread the problem. Duh. If you want to maintain order of the "removed" list as stated, then Boris' comment is right on regarding append/3. append(A, B, C) means that if you take A and append B you get C, with element order preserved.

So, to restate the solution as requested:

remove_elements(L1, L2, L) :-
    append(A, B, L1),
    append(C, L2, A),
    append(C, B, L).

Upvotes: 3

Related Questions