2011-03-03 150 views
8

我正在尝试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?同样,如何编写一些从列表中返回所需的满足要求的缺失值?

回答

18

你问了很多问题!让我让你开始解决大部分需求的谓词。

首先,让我们来解决检查一个列表的所有项目也都在其他名单的情况:

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

这简单而又重复利用熟悉的成员/ 2谓词来验证每个条目中子集/ 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). 

这个递归致力于通过列表中,由一个每个第一清单上的项目原来是在第二个列表以及时间递减的第三个参数,并成功一旦计数减少到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中,变量是以大写字母或下划线开头的标识符,所以如果列表中的项目被用作“未知数”而不是(正如我假定你的意思)不同的原子(常量)。切换到小写字母可以解决这个问题。

相关问题