如何从序言中的列表中删除列表?

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].