Prolog - 如何检查列表是否包含某些元素?

时间:2011-03-03 23:48:04

标签: list prolog

我是第一次尝试使用Prolog而且使用列表时遇到了一些困难。

说我有一个元素列表。我想检查列表是否包含以下元素:

全部:A1,A2,A3,A4,A5

其中一个:B1,B2,B3,B4

两个:C1,C2,C3,C4,C5,C6

例如,[A1,A2,B2,C1,A3,A4,C4,A5]符合要求,[A2,A1,C1,B1,A3,A4]不符合要求。

如果列表符合要求,我将如何编写返回Yes / True的内容,否则返回No / False?同样,如何编写从列表中返回缺失值的东西来满足要求呢?

1 个答案:

答案 0 :(得分:19)

你问了很多问题!让我开始介绍一些可以解决大部分需求的谓词。

首先让我们解决检查一个列表的所有条目是否也在另一个列表中的情况:

subset([ ],_).
subset([H|T],List) :-
    member(H,List),
    subset(T,List).

这个简单的递归利用熟悉的 member / 2 谓词来验证由 subset / 2 的第一个参数指定的列表中的每个条目也在列表中由第二个参数指定。 [为简单起见,我假设这些列表的条目是不同的。如果我们想要验证第一个列表的条目的多个实例是否与第二个列表中的至少那么多个实例匹配,则需要更复杂的版本。]

好吧,如果(至少)第一个列表中的一个列表也属于第二个列表,那该怎么办?显然,这是一个与上述不同的谓词。如果存在第一个列表中属于第二个列表的任何一个项目,则不满足第一个列表中的所有项目。

intersects([H|_],List) :-
    member(H,List),
    !.
intersects([_|T],List) :-
    intersects(T,List).

如果递归失败,如果它到达第一个参数的空列表,但是如果在找到属于第二个列表的第一个列表的成员之前的任何点,则成功。 [即使项目的多个实例出现在任一列表中,此谓词也能正常工作。但是,如果我们想要检查第一个列表中的正好一个项属于第二个列表,我们需要优化逻辑,这将需要担心多个实例是否与确切的一致或与之相反数一。]

如果我们想要概括此检查,以验证(至少)第一个列表中的N个项目是否在第二个项目中,该怎么办?结果谓词将需要第三个参数:

intersectsAtLeast(_,_,N) :- N <= 0, !.
intersectsAtLeast([H|T],L,N) :-
    member(H,L),
    !,
    M is N-1,
    intersectsAtLeast(T,L,M).
intersectsAtLeast([_|T],L,N) :-
    intersectsAtLeast(T,L,N).

此递归在列表中起作用,每当第一个列表上的项目也变为第二个列表时,第三个参数减1,并且一旦计数减少到0(或更少),则递增。 [如果列表可以重复,这里的代码再次需要更多的工作。]

最后,你要问写一些“返回缺失值”的东西需要满足要求。在检查两个列表上的一个或多个项目的情况下,这没有很好地定义,因为“缺失值”可能是许多可能项目中的任何一个。在我们要求第一个列表中的所有项目属于第二个列表的特殊情况下,可以确定“缺失值”(如果有的话)。

missingValues([ ],_,[ ]).
missingValues([H|T],L,K) :-
    member(H,L),
    !,
    missingValues(T,L,K).
missingValues([H|T],L,[H|K]) :-
    missingValues(T,L,K).

此处递归将项目从输入第一个列表“移动”到输出“缺失项目”第三个列表,当且仅当它们没有出现在第二个列表中时。

关于您的问题的最后一点注意事项。在Prolog中,变量是以大写字母或下划线开头的标识符,因此如果将那些被视为“未知数”而不是(因为我认为你的意思),那么使用A1,A2等作为列表中的项目就会遇到麻烦)不同的原子(常数)。切换到小写字母可以解决这个问题。

相关问题