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,但不允许定量说明符。