2013-12-10 62 views
3

我试图查看列表并计算给定单词出现的次数。我得到这个至今:序言 - 列表中的计数重复

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)]。我完全卡住了,有什么建议吗?

回答

4

你就在那里,在我看来。你可以简单地换你谓语另一个说:

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

+0

感谢您的解决方案鲍里斯。有X = [是 - 2]是我的一个错字,它不需要在括号中。再次感谢! – dlmb

6

此答案显示逻辑纯的方式来做到这一点。以下是根据

:- 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

 
?- N in 1..3, length(Xs,N). 
    N = 1, Xs = [_A] 
; N = 2, Xs = [_A,_B] 
; N = 3, Xs = [_A,_B,_C] 
...          % does not terminate 

?- use_module(library(lambda)). 
true. 

?- N in 1..3, tcount(\_^ =(true),Xs,N). 
    N = 1, Xs = [_A] 
; N = 2, Xs = [_A,_B] 
; N = 3, Xs = [_A,_B,_C] 
; false.         % terminates universally 
+1

很好的概括,但名称。好吧,这是一个崇高的计数。可能[Count von Count](https://www.google.com/search?q=count+count)。 – false

+0

Minor ditch:'tcount(Pred_1,List,Count): - list_pred_tcount(List,Pred_1,Count).'会在WAM上更好。然后,你的计数可以从0开始计数! – false

+1

更深的沟渠:'tcount(P_1,List,-1)' - 这个真的应该叫做“(P_1,X)”吗? – false

2

库(聚集体)通常被低估:

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,聚合/ 3允许更好地控制变量的量化(即,哪些值被聚合),但是如果没有解决方案将失败,而不是产生0,因为需要某个时间。

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