Prolog 序言计数频率

Prolog 序言计数频率,prolog,Prolog,是否可以编写一个谓词,它接受一个输入列表并输出一个带有键值对的输出列表 例如: freqs([a,b,a,a,b,c],L). L = [(a,3),(b,2),(c,1)] 如果可能的话,我更愿意这样做。我所知道的最远的就是这个 freqs([],[]). freqs(In,Out):- freqs(In,[],Out). freqs([],Out,Out). freqs([X|Xs],Table,Out):- \+ member((X,_),Table), fre

是否可以编写一个谓词,它接受一个输入列表并输出一个带有键值对的输出列表

例如:

freqs([a,b,a,a,b,c],L).
L = [(a,3),(b,2),(c,1)]
如果可能的话,我更愿意这样做。我所知道的最远的就是这个

freqs([],[]).
freqs(In,Out):-
    freqs(In,[],Out).

freqs([],Out,Out).
freqs([X|Xs],Table,Out):-
    \+ member((X,_),Table),
    freqs(Xs,[(X,1)|Table],Out).

freqs([X|Xs],Table,Out) :-
    member((X,N),Table),
    % stuck
更具体地说,如何增加N?
还有其他不需要辅助谓词的解决方案吗?

您可以使用公共库谓词select/3或selectchk/3(如果也可用),而不是member/2。类似于第三条:

freqs([X|Xs],Table,Out) :-
    selectchk((X,N),Table, Others),
    M is N + 1,
    freqs(Xs, [(X,M)| Others], Out).
但是,由于您似乎关心性能,如果将第二和第三个子句组合在一起,则速度会更快,从而生成以下完整的谓词定义:

freqs([], Out, Out).
freqs([X| Xs], Table, Out) :-
    (   select((X,N), Table, Others) ->
        M is N + 1,
        freqs(Xs, [(X,M)| Others], Out)
    ;   freqs(Xs, [(X,1)| Table], Out)
    ).
这样,对于每个输入列表元素,只需在表中查找一次X,N项

电话示例:

?- freqs([a,b,a,a,b,c],L).
L = [(c, 1),  (b, 2),  (a, 3)].

另一种解决方案是,首先使用标准的sort/2谓词对输入列表进行排序,这通常在logn上,然后遍历生成的排序列表一次,这当然是在logn上。如此类推*logn+的复杂性。但是,正如Will Ness所解释的,如果您的输入列表很大,则可能需要查看Prolog系统库以获得良好的字典实现。

您可以使用公共库谓词select/3或selectchk/3(如果还可用),而不是member/2。类似于第三条:

freqs([X|Xs],Table,Out) :-
    selectchk((X,N),Table, Others),
    M is N + 1,
    freqs(Xs, [(X,M)| Others], Out).
但是,由于您似乎关心性能,如果将第二和第三个子句组合在一起,则速度会更快,从而生成以下完整的谓词定义:

freqs([], Out, Out).
freqs([X| Xs], Table, Out) :-
    (   select((X,N), Table, Others) ->
        M is N + 1,
        freqs(Xs, [(X,M)| Others], Out)
    ;   freqs(Xs, [(X,1)| Table], Out)
    ).
这样,对于每个输入列表元素,只需在表中查找一次X,N项

电话示例:

?- freqs([a,b,a,a,b,c],L).
L = [(c, 1),  (b, 2),  (a, 3)].
另一种解决方案是,首先使用标准的sort/2谓词对输入列表进行排序,这通常在logn上,然后遍历生成的排序列表一次,这当然是在logn上。如此类推*logn+的复杂性。但是,正如Will Ness所解释的,如果您的输入列表很大,那么可能需要查看Prolog系统库以获得良好的字典实现。

以状态传递样式编写谓词函数,在遍历列表时更新表,就像在函数式编程语言中一样,制作一个修改过的副本,而不是一个不可能的值的变异

对于线性表,它当然是2

将其保持为一个开放的二叉搜索树,树的叶子上有未设置的logvars,当遇到一个新的键时,树将被扩展,这会像往常一样将复杂性降低到logn上。你的钥匙必须是可比的。原子是

关于可扩展查找表的示例,请参见这里的列表;使其成为树也是完全可行的。

以状态传递的方式编写谓词函数,在遍历列表时更新表,就像在函数式编程语言中一样,生成一个修改过的副本,而不是不可能的值变异

对于线性表,它当然是2

将其保持为一个开放的二叉搜索树,树的叶子上有未设置的logvars,当遇到一个新的键时,树将被扩展,这会像往常一样将复杂性降低到logn上。你的钥匙必须是可比的。原子是


关于可扩展查找表的示例,请参见这里的列表;把它变成一棵树也是完全可行的。

你能给出一些字典实现的示例链接吗?@WillNess一个候选字典实现将是YAP、SWI Prolog、Logtalk中的红黑树实现,可能还有其他实现。它提供了一个partial_map/4元谓词,该谓词接受一个可用于更新计数器的闭包。谢谢!你能给出一些字典实现的示例链接吗?@WillNess一个候选字典实现是YAP、SWI-Prolog、Logtalk中的红黑树实现,可能还有其他实现。它提供了一个partial_map/4元谓词,该谓词接受一个可用于更新计数器的闭包。谢谢!