统计相同元素Prolog

3

我想要在列表中计算一个元素,并在出现不同元素时停止计数,然后跳到下一个相同的元素。

答案应该是这样的:

?- count(a,[a,a,a,a,b,a,a,a],X).
X = [4,3]

?- count(a,[a,a,a,b,a,b,a,a,b,a,a,a,a],X).
X = [3,1,2,4]

我为count/3编写的代码是:
count(_, [], []).
count(X, [X | T], N) :-
   count(X, T, N1),
   !, 
   N is N1 + 1.
count(X, [_ | T], N) :-
   count(X, T, N).

我不知道如何让它返回一个数字列表。 有人能帮我吗? 谢谢。


2
你的问题相当模糊,所以我只能给你一个提示:使用4个参数而不是3个:2个用于输入,1个用于输出,还有1个用于当前找到的元素数量(初始为0)。 - Steven
@Kay,实际上我输入的列表只包含两个不同的元素,我想要计算其中一个元素的数量,并且结果应该只计算该元素。例如输入count(a,[a,a,a,b,a,b,a,a,b,a,a,a,a], X),输出X = [3,1,2,4]。 - Pei Chuang
2个回答

3

以下是如何实现并保留的方法!

在接下来的内容中,我们使用元谓词(splitlistIfAdj/3, tfilter/3maplist/3)和实化术语相等/不等谓词((=)/3dif/3)。

假设E = aXs0 = [a,a,a,b,a,b,a,a,b,a,a,a,a],我们逐步构建count/3

  1. 首先,让Xs1包含Xs0中项目的运行

    ?- Xs0 = [a,a,a,b,a,b,a,a,b,a,a,a,a], splitlistIfAdj(dif,Xs0,Xs1).
    Xs0 = [ a,a,a,  b,  a,  b,  a,a,  b,  a,a,a,a ],
    Xs1 = [[a,a,a],[b],[a],[b],[a,a],[b],[a,a,a,a]].
    

  2. 运行列表Xs1包含所有运行。让Xs2只包含我们感兴趣的运行:

    ?- Xs1 = [[a,a,a],[b],[a],[b],[a,a],[b],[a,a,a,a]], tfilter(\[X|_]^(X=a),Xs1,Xs2).
    Xs1 = [[a,a,a],[b],[a],[b],[a,a],[b],[a,a,a,a]],
    Xs2 = [[a,a,a],    [a],    [a,a],    [a,a,a,a]].
    

  3. 几乎完成了!最后,我们将Xs2(一个E-runs列表)映射到相应的运行长度Xs

    ?- Xs2 = [[a,a,a],[a],[a,a],[a,a,a,a]], maplist(length,Xs2,Xs).
    Xs2 = [[a,a,a],[a],[a,a],[a,a,a,a]],
    Xs  = [      3,  1,    2,        4].
    

现在,让我们把所有东西放在一起!

count(E,Xs0,Xs) :-
    splitlistIfAdj(dif,Xs0,Xs1),
    tfilter(E+\[X|_]^(X=E),Xs1,Xs2),   % 适用于 _任何_ 项目 E
    maplist(length,Xs2,Xs).

让我们运行一些查询:

?- count(a,[a,a,a,a,b,a,a,a],Xs).
Xs = [4,3].                            % succeeds deterministically
?- count(a,[a,a,a,b,a,b,a,a,b,a,a,a,a],Xs).
Xs = [3,1,2,4].                        % succeeds deterministically

由于代码是单调的,因此我们也可以为更一般的查询得到逻辑上正确的答案:
?- count(E,[a,a,a,b,a,b,a,a,b,a,a,a,a],Xs).
Xs = [3,1,2,4], E = a              ;
Xs = [1,1,1],   E = b              ;
Xs = [],        dif(E,a), dif(E,b) .

1

我回答中的想法是保持运行长度列表开放,并在运行结束时添加一个新元素:

count(_, [], []).
count(Item, [Head|Tail], Counts) :-
    count(Item, [Head|Tail], 0, Counts).
count(_, [], CurrentCount, [CurrentCount]).

count(Item, [Item|Tail], CurrentCount, Counts) :-
    CurrentCountP1 is CurrentCount + 1,
    count(Item, Tail, CurrentCountP1, Counts).
count(Item, [Head|Tail], CurrentCount, [CurrentCount|Counts]) :-
    dif(Head, Item),
    count(Item, Tail, 0, Counts).

?- count(a,[a,a,a,b,a,b,a,a,b,a,a,a,a], X).
X = [3, 1, 2, 4] ;
false.

当从 count/3count/4 时,您可以将输入列表移到第一个参数并使用 if-then-else 组合 count/4 的最后两个子句。这将消除样本查询中看到的虚假选择点(当然,假定在大多数系统中使用第一个参数索引)。 - Paulo Moura

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