覆盖两个列表的谓词

时间:2016-11-20 22:20:40

标签: list prolog

所以我正在制作一个倒计时游戏,我想检查一个列表是否包含另一个列表的元素。

给出两个列表,检查第二个列表是否涵盖第一个列表,即检查第一个列表中出现K次的每个项目是否也在第二个列表中出现至少K次:

实施例

cover([a,e,i,o], [m,o,n,k,e,y,b,r,a,i,n]).
Yes

cover([e,e,l], [h,e,l,l,o]).
no

我跟着一篇文章给了我大量的练习例子,到目前为止我做得还不错,但这个让我有些停滞不前。

我写过这个,

cover([],_).
cover([Head|Tail], List2):-
    member(Head, List2),
    cover(Tail, List2).

问题是,它没有考虑列表中的K次,

我一直在挠头几个小时, 任何指针都会很棒。

1 个答案:

答案 0 :(得分:2)

非常接近解决方案!

要完全解决它,请考虑member/2的轻微泛化:在这种情况下我们将使用的构建块与member/2非常相似,但具有以下扭曲:我们让第三个参数表示剩余列表是什么,我的意思是列表没有“成员”。

传统上,这个谓词被称为select/3,这是一个非常糟糕的名称,因为它表明我们只能在一个方向上使用谓词。这相当命令式

我将使用更具描述性的声明性名称并将其称为 selection/3

想想这样的关系

selection(E, [E|Ls], Ls).
selection(E, [L|Ls], [L|Rest]) :-
        selection(E, Ls, Rest).

您可以将member/2视为selection/3的特例,因为我们可以用member/2来定义selection/3,而不是关心剩余的列表:

member(E, Ls) :- selection(E, Ls, _).

使用selection/3,我们可以写:

list_cover([], _).
list_cover([L|Ls], Cs0) :-
        selection(L, Cs0, Cs),
        list_cover(Ls, Cs).

我们可以阅读第二条如下:

  

如果 LCs0的成员,则Cs是剩余列表(即Cs0没有L ), Cs涵盖Ls然后 Cs0涵盖[L|Ls]

请注意命名约定,理想情况下会明确每个参数的含义。在我们的例子中,第二个参数是覆盖列表。简单地称呼cover/2并不能说明哪个论点实际上代表了封面。

示例查询和答案:

?- list_cover([a,e,i,o], [m,o,n,k,e,y,b,r,a,i,n]).
true .

?- list_cover([a,a,a], [a,a]).
false.

?- list_cover([a,a,a], [a,a,b,a]).
true .

进一步说:

?- list_cover(Ls, Cs).
Ls = [] ;
Ls = [_1900],
Cs = [_1900|_1908] ;
Ls = [_1900, _1912],
Cs = [_1900, _1912|_1920] .

很酷,不是吗?这很普遍!