使用递归可以构建谓词remove_list/3,这是在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).
咨询:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
这个想法是将原始列表“L1”中的每个元素复制到最终列表“L”中,除非该元素是第二个列表“L2”的成员。
你的基本条款是停止条件,当原始列表“L1”为空时,在这种情况下忽略列表“L2”,结果始终为相同的空列表。(你不能从空列表中删除任何内容)。
第二个条款是,如果列表“L1”头部的元素是列表“L2”的成员,则不将该元素复制到最终列表“L”中,并使用列表“L”的尾部进行递归调用。
最后一个条款是将列表“L1”头部的元素复制到最终列表“L”中,并使用该列表的尾部进行递归调用。我们不需要goal member/2,因为我们在前一个条款中使用了cut。
编辑: 如果您想要从列表“L1”中删除包含在“L2”列表中的项目(无论顺序如何),请使用
Lurker's 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).
这个新的解决方案会考虑列表"L2"中元素的顺序,但并不是严格意义上的顺序,也就是说,它可以穿插在原始列表"L1"中,这并不违反"L2"是"L1"子集的概念。
[2,4]是[1,2,3,4,5,6]集合的子集,但[2,4,7]不是:
?- 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.
现在,考虑到我们希望得到原始集而不是消极响应,在原始集中的任何一个元素可以被删除的情况下,我们使用辅助谓词:
rm_subset(L1, L2, L):- remove_list(L1, L2, L),!.
rm_subset(L1, L2, L1).
咨询:
?- 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].
append/3
不会删除元素,如果它们与原始列表中的顺序不同。我可能应该编辑我的答案... - Yasel