进行序言分配。
我有一个结构cnt(letter,number).
我需要返回cnt
的列表,其中每个cnt
是每个字符出现的次数(假设每个项目已经被排序以将相同的项目一个接一个地放置)。
到目前为止,我有这个:
cnt(letter,number).
freq([],[]).
freq([A|L],Y) :- grab(A,Init,_), freq(L,[Init|Y]).
抓取工作正确获取项目列表并将第一个重复项列表返回为Init
例如grab([a,a,a,b,c], Init, Rest).
将返回Init = [a,a,a]
。
假设我有一个列表[a,a,a,b,b,b,c,c]
我需要freq才能返回Y = [cnt(a,3), cnt(b,3), cnt(c,2)].
我认为我到目前为止接近正确,除了它返回false。
反正有没有办法看看它到底做了什么?或者任何人都可以看到任何明显的问题。
答案 0 :(得分:7)
让我们从你的定义开始,这已经非常接近你想要的了。
freq([],[]).
freq([A|L],Y) :- grab(A,Init,_), freq(L,[Init|Y]).
freq/2
在此为列表中的每个元素定义。为了看到这一点,我将看一下你定义的以下部分:
freq([],_).
freq([A|L],_) :- ..., freq(L,_).
这是你想要的吗?您说该列表仅包含相同的元素。因此,如果我们有[a,a]
,您确实希望此freq/2
应用一次,而不是两次。
另一个问题是这个。同样,我只关注你的计划的一部分:
freq(_,[]).
freq(_,Y) :- ..., freq(_,[Init|Y]).
所以你在这里有一个目标freq(_,[Init|Y])
,它在第二个参数中有一个至少一个元素的列表。您是否在定义中看到适用于此类列表的任何条款?事实freq(_,[]).
永远不会适用,所以剩下的唯一规则是此目标出现的规则。简而言之,目标freq(_,[Init|Y])
永远不会成功。无论Init
和Y
是什么。
现在是您的更正版本,几乎是您想要的版本:
freq([],[]).
freq([A|L],[As|Y]) :-
grab([A|L],As,K),
freq(K,Y).
让我们看看:
?- freq([a,a,a,b,b,b,c,c],Ys).
Ys = [[a,a,a],[b,b],[c,c]].
因此,我们需要一个具有列表字符和长度的结构cnt(a,3)
,而不是列表中的那些元素。
freq([],[]).
freq([A|L],[cnt(A,N)|Y]) :-
grab([A|L],As,K),
length(As, N),
freq(K,Y).
答案 1 :(得分:4)
我会尝试解释你能做些什么(抱歉我的英语不好)。
您的基本案例 freq([],[])看起来不错,但您想要计算元素,因此它将是
freq([], [cnt(0, _)])
看起来很奇怪。
有趣的是只有一个元素的列表的基本情况:
freq([A], [cnt(1,A)]).
现在,在我们处理列表的Prolog中,我们保留第一个元素并处理列表的其余部分,然后我们查看结果:
freq([A | T], R) :-
freq(T, R1),
process(A, R1, R).
现在,R1如何,两种可能性:R1 = [cnt(V,A)| L]或R1 = [cnt(V,B)| L],A与B不同。
所以我们可以写
process(A, [cnt(V, A)|L], [cnt(V1, A) | L]) :-
V1 is V+1.
process(A, [cnt(V, B)|L], [cnt(1, A), cnt(V, B) | L]) :-
A \= B.
答案 2 :(得分:0)
我会这样做(假设列表已经订购)
frequency( [] , [] ) . % the frequency table for the empty list is the empty list
frequency( [X|Xs] , F ) :- % for a non-empty list,
tabulate( Xs , X:1 , F ) % we just invoke the tabulation predicate, seeding the accumulator with the initial count.
. %
tabulate( [] , C:N , [C:N] ) . % if the source list is exhausted, we're done: shift the accumulator to the result list.
tabulate( [X|Xs] , X:N , F ) :- % otherwise,
! , % - and we haven't yet hit a sequence break,
N1 is N+1 , % - increment the frequency
tabulate( Xs , X:N1 , F ) % - and recurse down.
. %
tabulate( [X|Xs] , C:N , [C:N|F] ) :- % finally, if we have a sequency break: shift the accumulator to the result list
tabulate( Xs , X:1 , F ) % and recurse down
. %
这会对列表进行排序,然后对列表进行一次传递,并按照我们的计算进行计算。