首页 > 解决方案 > 确定第一个列表的所有成员是否都是第二个列表的成员

问题描述

如果第一个列表中的所有成员都是第二个列表的成员,则我无法启动此 Prolog 程序,该程序需要两个列表并返回 true,否则返回 false。

例子:

?- members([a, c], [a, b, c, d])
true
?- members([d, a, c, a], [a, b, c, d, e])
true
?- members([b, e], [a, b, c, d])
false
?- members([], [a, b, c, d])
true

我该怎么做呢?任何帮助表示赞赏。

标签: listprolog

解决方案


您可以使用maplist此类问题,因为它遵循标准的递归列表遍历:

mem(L, X) :- memberchk(X, L).
subset(S, L) :- maplist(mem(L), S).

结果:

| ?- subset([a,c], [a,b,c,d]).

yes
| ?- subset([c,a], [a,b,c,d]).

yes
| ?- subset([e], [a,b,c,d]).

no
| ?- subset([], [a,b,c,d]).

yes
| ?- subset(S, [a,b,c,d]), S=[_|_].

S = [a] ? ;

S = [a,a] ? ;

S = [a,a,a] ? ;
...

请注意,原始问题定义不排除子集可以具有来自超集的重复元素的情况。如果要将子集限制为元素数小于或等于超集,可以使用select/3

subset([], _).
subset([X|Xs], L) :-
    select(X, L, L1),
    subset(Xs, L1).

结果:

| ?- subset([a,c], [a,b,c,d,e]).

true ? ;

no
| ?- subset([a,f], [a,b,c,d,e]).

no
| ?- subset([a,a], [a,b,c,d,e]).

no
| ?- subset(S, [a,b,c]), S=[_|_].

S = [a] ? ;

S = [a,b] ? ;

S = [a,b,c] ? ;

S = [a,c] ? ;

S = [a,c,b] ? ;

S = [b] ? ;

S = [b,a] ? ;
...

S = [c,b] ? ;

S = [c,b,a] ? ;

no

您会注意到该[c,b,a]列表在 Prolog 中被视为不同的列表,[a,b,c]因此它是一个单独的解决方案。如果您想让列表真正表现得像集合,那么这是一个不同的解决方案。


推荐阅读