我想在prolog中实现以下问题:
给定
L1=[1,2,3,4] and L2=[2,3,4]
一个名为remove_list(L1,L2,L)的函数将从L1中删除L2.
所以L将是[1].但是如果第二个列表的元素与L1中的元素顺序不同,或者更准确地说第二个元素不是第一个List的子集,则它不会删除任何内容.
说L1=[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]
任何帮助将受到高度赞赏.提前致谢
您可以使用递归来构建谓词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).
Run Code Online (Sandbox Code Playgroud)
请教:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
Run Code Online (Sandbox Code Playgroud)
我们的想法是将原始列表"L1"中的每个元素复制到最终列表"L",除非该元素是第二个列表"L2"的成员.
您的基本条款是您的停止条件,当您的原始列表"L1"为空时,在这种情况下忽略您的列表"L2",结果始终是相同的空列表.(您无法从空列表中删除任何内容).
你的第二个子句,如果头部中的元素是列表"L2"的成员,则不要将列表"L1"的头部中的元素复制到最终列表"L",也要对谓词进行递归调用.你的清单"L"的尾巴.
最后一个子句,将列表"L1"的头部中的元素复制到最终列表"L",并且还使用该列表的尾部"L"对谓词进行递归调用.我们在这里不需要目标成员/ 2,因为我们在前一个子句中使用了cut.
编辑:只有在您想要从"L2"列表中包含的列表"L1"中删除项目时才应考虑此答案,无论顺序如何.要从集合"L1"中删除子集"L2",请使用Lurker的解决方案或其他解决方案:
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).
Run Code Online (Sandbox Code Playgroud)
这个新的解决方案考虑了列表"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.
Run Code Online (Sandbox Code Playgroud)
现在,考虑到在原始集合中的任何元素都可以被删除的情况下希望获得原始集合而不是负面响应的事实,那么我们使用辅助谓词:
rm_subset(L1, L2, L):- remove_list(L1, L2, L),!.
rm_subset(L1, L2, L1).
Run Code Online (Sandbox Code Playgroud)
请教:
?- 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].
Run Code Online (Sandbox Code Playgroud)