Prolog从列表中删除多个元素

5

我知道如何从列表中删除一个元素,但是否有一种方法可以从列表中删除多个元素?例如,

deletelist([a,b,c,a,b],[a,c],X)
X = [b,b] % delete a and c from the list.
5个回答

5

SWI-Prolog 提供了 subtract/3 函数:

?- subtract([a,b,c,a,b], [a,c], X).
X = [b, b].

?- listing(subtract).
lists:subtract([], _, []) :- !.
lists:subtract([A|C], B, D) :-
    memberchk(A, B), !,
    subtract(C, B, D).
lists:subtract([A|B], C, [A|D]) :-
    subtract(B, C, D).

3
为了删除多个元素,我们要检查第二个列表中是否存在该元素,并在条件为true时将其删除:
deletelist([], _, []).                  
deletelist([X|Xs], Y, Z) :- member(X, Y), deletelist(Xs, Y, Z), !.
deletelist([X|Xs], Y, [X|Zs]) :- deletelist(Xs, Y, Zs).

我会把!放在member和deleteList之间。 - Vincent Cantin
1
deletelist([a],[a],[a]). 成功了,但它应该失败。 - false

1
这里是一个始终能够产生正确答案的定义(除了终止之外):
deletelist(Xs, Ys, Zs) :-
   tfilter(not(list_memberd_truth(Ys)),Xs, Zs).

not(G, E, T) :-
   call(G, E, NT),
   ( NT = true, T = false
   ; NT = false, T = true
   ).

list_memberd_truth(Xs, X, Truth) :-
   memberd_truth(X, Xs, Truth).

使用其他答案中的tfilter/3memberd_truth/3。 如果您的Prolog不支持dif/2,请参见iso_dif/2以进行安全近似。

一些更不寻常的问题仍然是正确的:

?- deletelist([a], [X], Zs).
   X = a, Zs = []
;  Zs = [a], dif(X, a)
;  false.
?- deletelist([X], [Y], [X]).
   dif(X, Y)
;  false.

以下是一些应该失败(并因此终止)但却循环的查询。请注意,循环远比给出错误答案要好。

?- deletelist([a], Zs, Zs).
   error(resource_error(local_stack),_).

?- deletelist(Xs, Xs, Xs).
   Xs = []
;  error(resource_error(local_stack),_).

0

% sorry!

deletelist(Xs,Ys,Zs) :-
        findall(A,(
                    member(A,Xs),
                    \+(member(A,Ys))),
                Zs).

0
deletelist(Xs,[],Xs).
deletelist(Xs,[Y|Ys],Zs):-
    delete(Xs,Y,As),
    deletelist(As,Ys,Zs).

要从列表中删除单个元素,可以使用一个名为'delete/3'的库函数。它接受一个列表和要从该列表中删除的项目,并返回已删除该项目的新列表。我已经利用了这个函数,并在需要从列表中删除项目的项上进行了递归。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接