Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove a list from a list in prolog?

Tags:

list

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

like image 471
Alvi Avatar asked Jan 09 '23 16:01

Alvi


1 Answers

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].
like image 179
Yasel Avatar answered Jan 15 '23 05:01

Yasel