Prolog获得列表的频率

时间:2014-06-08 00:32:43

标签: prolog

进行序言分配。

我有一个结构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。

反正有没有办法看看它到底做了什么?或者任何人都可以看到任何明显的问题。

3 个答案:

答案 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])永远不会成功。无论InitY是什么。

现在是您的更正版本,几乎是您想要的版本:

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
  .                                   %

这会对列表进行排序,然后对列表进行一次传递,并按照我们的计算进行计算。