Prolog – 在列表中统计重复次数

我试图查看一个列表,并计算给定单词出现的次数。 我到目前为止:

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)]的forms输出一个包含search词和出现次数的列表。 我完全卡住了,有什么build议?

你已经在我身上了。 你可以简单地将你的谓词包装在另一个谓词中:

 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而不是两个不同的子句。 你可以把答案放在一个列表中,如果你想(只是将参数包括在方括号中),但是又是不必要的。

这个答案显示了一个逻辑上纯粹的方式来做到这一点。 以下是基于clpfd 。

 :- use_module(library(clpfd)). 

我们同tfilter/3一样定义元谓词 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). 

现在让我们用(=)/3结合使用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. 

接下来的angular落案例呢?

 ?- 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]
 ...% 不会终止

 ? -  use_module(library(lambda))。
真正。

 N = 1..3, tcount (\ _ ^ =(true),Xs,N)。
   N = 1,Xs = [_A]
 ;  N = 2,Xs = [_A,_B]
 ;  N = 3,Xs = [_A,_B,_C]
 ;  假。终止普遍

图书馆(聚合)往往被低估:

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

产量

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

所以,更简单

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

产量

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

基于setof,aggregate / 3允许更好地控制variables的量化(即哪些值被聚合),但是如果没有解决scheme,将会失败,而不是产生0,因为需要某个时间。

基于findall / 3的aggregate_all / 3将在这种情况下返回0,但不允许定量说明符。