如何从prolog列表中删除列表?

时间:2015-03-24 17:44:34

标签: list prolog

我想在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]
任何帮助将受到高度赞赏。 提前致谢

3 个答案:

答案 0 :(得分: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”,结果始终是相同的空列表。 (您无法从空列表中删除任何内容) 你的第二个子句,如果头部中的元素是列表“L2”的成员,则不要将列表“L1”的头部中的元素复制到最终列表“L”,也要对谓词进行递归调用。你的清单“L”的尾巴 最后一个子句,将列表“L1”的头部中的元素复制到最终列表“L”,并且还使用该列表的尾部“L”对谓词进行递归调用。我们在这里不需要目标成员/ 2,因为我们在前一个条款中使用过切割。

编辑:只有在您想要从“L2”列表中包含的列表“L1”中删除项目时才应考虑此答案,无论顺序如何。要从“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].

答案 1 :(得分:3)

另一种可能的解决方案,使用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
| ?-

<小时/> 编辑我刚刚意识到我完全误解了这个问题。咄。如果你想保持&#34;删除&#34;的顺序如上所述,然后鲍里斯&#39;有关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).

答案 2 :(得分:0)

通常,如果您只想从另一个列表中删除一个列表中的多个元素,则可以使用:

subtract(+Set, +Delete, -Result)

其中set =无序列表,可以包含一些重复的元素,并且 delete =我们要从Set中删除的元素列表。

例如:

subtract([1,3,5,6,4,2,3], [1,2,3], R).
R = [5, 6, 4].