如何从序言中的列表中删除列表?
How to remove a list from a list in prolog?
我想在序言中实现以下问题:
给定
L1=[1,2,3,4] and L2=[2,3,4]
调用名为 remove_list(L1,L2,L) 的函数将从 L1 中删除 L2。
因此 L 将为 [1]。
但是,如果第二个列表的元素与 L1 中的元素顺序不同,或者更准确地说,第二个列表不是第一个列表的子集,它不会删除任何内容。
说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).
咨询:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
想法是将原始列表 "L1" 中的每个元素复制到最终列表 "L",除非该元素是第二个列表的成员 "L2".
您的基本子句是您的停止条件,当您的原始列表 "L1" 为空时,在这种情况下忽略您的列表 "L2",结果始终是相同的空列表。 (您不能从空列表中删除任何内容)。
你的第二个子句,不要将列表头部的元素 "L1" 复制到最终列表 "L" 如果头部中的元素是列表 "L2" 的成员,也使使用列表的尾部递归调用谓词 "L".
最后一个子句,将列表 "L1" 头部的元素复制到最终列表 "L",并使用该列表的尾部 "L" 对谓词进行递归调用。我们这里不需要目标 member/2,因为我们在前面的子句中使用了 cut。
编辑: 只有当您想从 "L2" 列表中包含的列表 "L1" 中删除项目时,才应考虑此答案,无论命令。要从集合 "L1" 中删除子集 "L2",请使用 或其他解决方案:
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].
另一个可能的解决方案,使用 delete/3
谓词:
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
| ?-
编辑 我刚刚意识到我完全误解了这个问题。呃。如果您想按规定维护 "removed" 列表的顺序,那么 Boris 对 append/3
的评论是正确的。 append(A, B, C)
意味着如果你使用 A
并追加 B
你会得到 C
,并保留元素顺序。
因此,根据要求重述解决方案:
remove_elements(L1, L2, L) :-
append(A, B, L1),
append(C, L2, A),
append(C, B, L).
一般来说,如果你只想从另一个列表中删除一个列表中的多个元素,你可以使用:
subtract(+Set, +Delete, -Result)
where set = unorderd list which can have some duplicated elements and
delete = 我们要从 Set 中删除的元素列表。
例如:
subtract([1,3,5,6,4,2,3], [1,2,3], R).
R = [5, 6, 4].
我想在序言中实现以下问题:
给定
L1=[1,2,3,4] and L2=[2,3,4]
调用名为 remove_list(L1,L2,L) 的函数将从 L1 中删除 L2。
因此 L 将为 [1]。
但是,如果第二个列表的元素与 L1 中的元素顺序不同,或者更准确地说,第二个列表不是第一个列表的子集,它不会删除任何内容。
说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).
咨询:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
想法是将原始列表 "L1" 中的每个元素复制到最终列表 "L",除非该元素是第二个列表的成员 "L2".
您的基本子句是您的停止条件,当您的原始列表 "L1" 为空时,在这种情况下忽略您的列表 "L2",结果始终是相同的空列表。 (您不能从空列表中删除任何内容)。
你的第二个子句,不要将列表头部的元素 "L1" 复制到最终列表 "L" 如果头部中的元素是列表 "L2" 的成员,也使使用列表的尾部递归调用谓词 "L".
最后一个子句,将列表 "L1" 头部的元素复制到最终列表 "L",并使用该列表的尾部 "L" 对谓词进行递归调用。我们这里不需要目标 member/2,因为我们在前面的子句中使用了 cut。
编辑: 只有当您想从 "L2" 列表中包含的列表 "L1" 中删除项目时,才应考虑此答案,无论命令。要从集合 "L1" 中删除子集 "L2",请使用
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].
另一个可能的解决方案,使用 delete/3
谓词:
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
| ?-
编辑 我刚刚意识到我完全误解了这个问题。呃。如果您想按规定维护 "removed" 列表的顺序,那么 Boris 对
append/3
的评论是正确的。 append(A, B, C)
意味着如果你使用 A
并追加 B
你会得到 C
,并保留元素顺序。
因此,根据要求重述解决方案:
remove_elements(L1, L2, L) :-
append(A, B, L1),
append(C, L2, A),
append(C, B, L).
一般来说,如果你只想从另一个列表中删除一个列表中的多个元素,你可以使用:
subtract(+Set, +Delete, -Result)
where set = unorderd list which can have some duplicated elements and delete = 我们要从 Set 中删除的元素列表。
例如:
subtract([1,3,5,6,4,2,3], [1,2,3], R).
R = [5, 6, 4].