【问题标题】:Prolog count frequenciesProlog计数频率
【发布时间】:2018-08-22 13:46:26
【问题描述】:

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

示例:

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

如果可能,我更愿意在 O(n) 中执行此操作。我得到的最远的是这个

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? 还有其他不需要辅助谓词的解决方案吗?

【问题讨论】:

    标签: prolog


    【解决方案1】:

    您可以使用公共库谓词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 谓词对输入列表进行排序,通常为 O(n log(n)),然后遍历生成的排序列表一次,当然,这将是 O (n)。所以 O(n*log(n)) + O(n) 复杂度。但是,正如 Will Ness 所解释的,如果您的输入列表很大,那么可能值得研究您的 Prolog 系统库以获得良好的 dictionary 实现。

    【讨论】:

    • 你能给那些字典实现的一些示例链接吗?
    • @WillNess 一个候选字典实现将是在 YAP、SWI-Prolog、Logtalk 以及可能的其他人中发现的红黑树实现。它提供了一个partial_map/4 元谓词,它采用可用于更新计数器的闭包。
    • 感谢reference
    【解决方案2】:

    以状态传递样式编写谓词函数,在遍历列表时更新表,就像在函数式编程语言中所做的那样,制作更改后的副本而不是(不可能的)值的突变。

    对于线性表,它当然是O(n2)

    将其维护为开放的二叉搜索树(在叶子上使用未实例化的 logvar,以便在遇到新键时扩展树)将复杂度降低到 O(n log n) 像往常一样。为此,您的密钥必须具有可比性。原子是。

    请参阅attr/2 以获取可扩展查找表的示例(只是它是一个列表,在那里;将其变成一棵树也是完全可行的)。

    【讨论】:

      猜你喜欢
      • 2012-11-04
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      相关资源
      最近更新 更多