【问题标题】:Prolog - count repetitions in listProlog - 计算列表中的重复次数
【发布时间】:2013-12-27 08:42:06
【问题描述】:

我正在尝试查看列表并计算给定单词出现的次数。到目前为止我已经得到了这个:

count_repetitions([_], [], 0).
count_repetitions([Word], [Word|Tail], Count):-
   count_repetitions([Word], Tail, X), 
   Count is X + 1.
count_repetitions([Word], [Z|Tail], Count):-
   Word \= Z, 
   count_repetitions([Word], Tail, Count).

所以查询?- count_repetitions([yes],[yes,and,yes,and,no], X). 将给出X = 2

这似乎有效。现在我需要编写一个谓词,输出一个包含搜索词及其出现次数的列表,格式为X = [(yes - 2)]。我完全被卡住了,有什么建议吗?

【问题讨论】:

    标签: list prolog


    【解决方案1】:

    这个答案显示了一种逻辑上纯粹的方法。以下内容基于

    :- use_module(library(clpfd)).
    

    我们定义 tcount/3 类似于tfilter/3

    :- meta_predicate tcount(2,?,?).
    tcount(P_2,Xs,N) :-
       N #>= 0,
       list_pred_tcount_(Xs,P_2,0,N).
    
    :- meta_predicate list_pred_tcount_(?,2,?,?).
    list_pred_tcount_([]    , _ ,N ,N).
    list_pred_tcount_([X|Xs],P_2,N0,N) :-
       if_(call(P_2,X), (N1 is N0+1, N1 #=< N), N1 = N0),
       list_pred_tcount_(Xs,P_2,N1,N).
    

    现在让我们将tcount/3(=)/3 结合使用:

    ?- tcount(=(yes),[yes,and,yes,and,no],Count).
    Count = 2.
    

    所有此问题的其他答案提供的代码不同,此答案中提供的代码是单调,即使与非基本术语一起使用也能保持逻辑合理:

    ?- tcount(=(yes),[A,B,C,D],2).
          A=yes ,     B=yes , dif(C,yes), dif(D,yes)
    ;     A=yes , dif(B,yes),     C=yes , dif(D,yes)
    ;     A=yes , dif(B,yes), dif(C,yes),     D=yes
    ; dif(A,yes),     B=yes ,     C=yes , dif(D,yes)
    ; dif(A,yes),     B=yes , dif(C,yes),     D=yes
    ; dif(A,yes), dif(B,yes),     C=yes ,     D=yes
    ; false.
    

    让我们尝试一些更通用的方法:

    ?- tcount(=(yes),[A,B,C,D],Count).
          A=yes ,     B=yes ,     C=yes ,     D=yes , Count = 4
    ;     A=yes ,     B=yes ,     C=yes , dif(D,yes), Count = 3
    ;     A=yes ,     B=yes , dif(C,yes),     D=yes , Count = 3
    ;     A=yes ,     B=yes , dif(C,yes), dif(D,yes), Count = 2
    ;     A=yes , dif(B,yes),     C=yes ,     D=yes , Count = 3
    ;     A=yes , dif(B,yes),     C=yes , dif(D,yes), Count = 2
    ;     A=yes , dif(B,yes), dif(C,yes),     D=yes , Count = 2
    ;     A=yes , dif(B,yes), dif(C,yes), dif(D,yes), Count = 1
    ; dif(A,yes),     B=yes ,     C=yes ,     D=yes , Count = 3
    ; dif(A,yes),     B=yes ,     C=yes , dif(D,yes), Count = 2
    ; dif(A,yes),     B=yes , dif(C,yes),     D=yes , Count = 2
    ; dif(A,yes),     B=yes , dif(C,yes), dif(D,yes), Count = 1
    ; dif(A,yes), dif(B,yes),     C=yes ,     D=yes , Count = 2
    ; dif(A,yes), dif(B,yes),     C=yes , dif(D,yes), Count = 1
    ; dif(A,yes), dif(B,yes), dif(C,yes),     D=yes , Count = 1
    ; dif(A,yes), dif(B,yes), dif(C,yes), dif(D,yes), Count = 0.
    

    下面的极端情况呢?

    ?- tcount(_,_,-1).
    false.
    

    那么使用tcount/3 作为length/2 的替代品怎么样?

    ?- 1..3 中的 N,长度(Xs,N)。 N = 1,Xs = [_A] ; N = 2, Xs = [_A,_B] ; N = 3, Xs = [_A,_B,_C] ... % 不终止 ?- 使用模块(库(lambda))。 真的。 ?- 1..3 中的 N,tcount(\_^ =(true),Xs,N)。 N = 1,Xs = [_A] ; N = 2, Xs = [_A,_B] ; N = 3, Xs = [_A,_B,_C] ;错误。 % 普遍终止

    【讨论】:

    • 很好的概括,但名称。好吧,这是关于贵族的。可能是Count von Count
    • 更进一步:tcount(P_1, List, -1) - 这真的应该叫call(P_1,X)吗?
    • 出现错误!应该是:- meta_predicate tcount(2,?,?).
    • @false。 Thx 4 指出这一点!现在应该好多了。
    • 不利于N in 1..3, length(Xs,N). 的终止。这是由于 length/2 提出了越来越大的 N,但是对 N 的约束禁止任何超过 3 的实例化尝试失败。约束中应该有一些东西告诉 length/2 它永远不会以这种方式找到解决方案。
    【解决方案2】:

    在我看来,你已经在那里了。你可以简单地将你的谓词换成另一种说法:

    word_repetitions(Word, List, [(Word-Count)]) :-
        count_repetitions(Word, List, Count).
    

    请注意,Word-Count 对不需要括号或方括号:

    word_repetitions(Word, List, Word-Count) :-
        count_repetitions(Word, List, Count).
    

    (但如果你坚持,你可以使用它们)。

    在原始谓词上,重命名以反映差异:

    list_word_reps([], Word, Word-0).
    list_word_reps([W|Rest], Word, Word-Reps) :-
        list_word_reps(Rest, Word, Word-Reps0),
        (   W == Word
        ->  Reps is Reps0 + 1
        ;   Reps = Reps0
        ).
    
    ?- list_word_reps([yes,no,yes,no,maybe,yes], yes, X).
    X = yes-3.
    

    列表出现在单词之前的原因是谓词因此变得确定性。使用 if-then-else 而不是两个不同的子句也是如此。如果您愿意,您可以将答案放在一个列表中(只需将参数括在括号中),但同样没有必要。

    【讨论】:

    • 感谢您的解决方案 Boris。有 X = [yes - 2] 对我来说有点错别字,它不需要放在括号中。再次感谢!
    【解决方案3】:

    图书馆(聚合)经常被低估:

    count(L, C) :-
        aggregate(set(W-N), aggregate(count, member(W, L), N), C).
    

    产量

    1 ?- count([a,b,a],C).
    C = [a-2, b-1].
    

    所以,越简单

    count(W, L, W-N) :-
        aggregate(count, member(W, L), N).
    

    产量

    ?- count(a, [a,b,a], C).
    C = a-2.
    

    基于 setof,aggregate/3 允许更好地控制变量的量化(即聚合哪些值),但如果没有解决方案,则会失败,而不是在某些时候需要产生 0。

    aggregate_all/3,基于 findall/3,在这种情况下会返回 0,但不允许使用量化说明符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      相关资源
      最近更新 更多