计算Prolog中连续出现的数字

时间:2014-11-20 21:03:54

标签: list prolog run-length-encoding

您好我正在尝试在Prolog中创建一个程序,该程序给出一个列表,它按列表计算列表中每个连续元素的出现次数:

count(1,[1,1,1,2,2,2,3,1,1],0,X)

结果将是X=[ [1,3],[2,3],[3,1][1,2] ] 又名每个子列表是[element,occurrences]

在我的情况下,我认为基本情况有问题,但我无法解决。你能救我吗?

%append an element to a list
append([ ],Y,Y).
append([X|Xs],Ys,[X|Zs]):-append(Xs,Ys,Zs).

%c is the counter beginning with 0 
count(_,[],_,[]).
count(X,[X],C,[L]):-count(X,[],C,[L|[X,C]]).

%increase counter
count(X,[X|Tail],C,L):-Z is C+1,count(X,Tail,Z,L).
count(X,[Head|Tail],C,[L]):-append(L,[X,C],NL),count(Head,Tail,1,NL).

5 个答案:

答案 0 :(得分:2)

我们可以解决您的问题保留

在下面,让Xs[1,1,1,2,2,2,3,1,1],即您在问题中使用的列表。

首先,我们将Xs映射到列表Yss,以便Ys中的每个列表Yss仅包含取自的相同元素Xs。 我们通过将元谓词splitlistIfAdj/3与具体化的不等式谓词dif/3结合使用来实现这一点:

?- Xs = [1,1,1,2,2,2,3,1,1], splitlistIfAdj(dif,Xs,Yss).
Xs  = [ 1,1,1,  2,2,2,  3,  1,1 ],
Yss = [[1,1,1],[2,2,2],[3],[1,1]].

第二次,我们将列表Yss映射到ZssZss中的每个项目都具有[Element,Amount]形式。 查看上述查询的答案,我们发现我们需要做的就是将[1,1,1]映射到[1,3],将[2,2,2]映射到[2,3],将[3]映射到{{ 1}}和[3,1][1,1][1,2]正是这样做的:

run_pair/2

在meta-predicate maplist/3的帮助下,让我们使用run_pair(Ys,[Element,Amount]) :- Ys = [Element|_], length(Ys,Amount). 来映射run_pair/2的每个项目:

?- Yss = [[1,1,1],[2,2,2],[3],[1,1]], maplist(run_pair,Yss,Zss).
Yss = [[1,1,1],[2,2,2],[3]  ,[1,1]],
Zss = [[1,3],  [2,3],  [3,1],[1,2]].

完成!把时间放在一起的时间:

Yss

让我们看看上面的查询是否仍然有效:)

count(Xs,Zss) :-
   splitlistIfAdj(dif,Xs,Yss),
   maplist(run_pair,Yss,Zss).

由于?- count([1,1,1,2,2,2,3,1,1],Zss). Zss = [[1,3],[2,3],[3,1],[1,2]]. % succeeds deterministically 的实施是单调,即使使用非基础术语,我们也能获得逻辑上合理的答案。让我们看看它在行动!

count/2

答案 1 :(得分:2)

这是另一种基于进行游程编码的尝试!

:- use_module(library(clpfd)).

基于if_/3(=)/3,我们定义list_rle/2

list_rle([],[]).
list_rle([X|Xs],[N*X|Ps]) :-
   list_count_prev_runs(Xs,N,X,Ps).

list_count_prev_runs(Es,N,X,Ps) :-
   N #> 0,
   N #= N0+1,
   list_count_prev_runs_(Es,N0,X,Ps).

list_count_prev_runs_([],0,_,[]).
list_count_prev_runs_([E|Es],N,X,Ps0) :-
   if_(X=E, 
       list_count_prev_runs(Es,N,X,Ps0),
       (N = 0, Ps0 = [M*E|Ps], list_count_prev_runs(Es,M,E,Ps))).

示例查询:

  • 编码/解码#1

    ?- list_rle([a,a,b,c,c,c,d,e,e],Ys).
    Ys = [2*a,1*b,3*c,1*d,2*e].
    
    ?- list_rle(Xs,[2*a,1*b,3*c,1*d,2*e]).
      Xs = [a,a,b,c,c,c,d,e,e]
    ; false.
    
  • 编码/解码#2

    ?- dif(A,B),dif(B,C),dif(C,D),dif(D,E), list_rle([A,A,B,C,C,C,D,E,E],Ys).
    Ys = [2*A,1*B,3*C,1*D,2*E], dif(A,B), dif(B,C), dif(C,D), dif(D,E).
    
    ?- list_rle(Xs,[2*A,1*B,3*C,1*D,2*E]).
      Xs = [A,A,B,C,C,C,D,E,E], dif(A,B), dif(B,C), dif(C,D), dif(D,E)
    ; false.
    
  • 一般情况怎么样?

    ?- list_rle([A,B,C,D],Xs).
      Xs = [4*A            ],     A=B ,     B=C ,     C=D
    ; Xs = [3*A,        1*D],     A=B ,     B=C , dif(C,D)
    ; Xs = [2*A,    2*C    ],     A=B , dif(B,C),     C=D
    ; Xs = [2*A,    1*C,1*D],     A=B , dif(B,C), dif(C,D)
    ; Xs = [1*A,3*B        ], dif(A,B),     B=C ,     C=D
    ; Xs = [1*A,2*B,    1*D], dif(A,B),     B=C , dif(C,D)
    ; Xs = [1*A,1*B,2*C    ], dif(A,B), dif(B,C),     C=D   
    ; Xs = [1*A,1*B,1*C,1*D], dif(A,B), dif(B,C), dif(C,D).
    

答案 2 :(得分:1)

为什么要说明具有4个参数的谓词的两个列表之间的关系?让我们一步一步地尝试。

空列表给出一个空列表,计算的元素递增,否则,开始计数......

count([],[]).
count([X|T],[[X,C1]|R]) :- count(T,[[X,C]|R]), !, C1 is C+1.
count([X|T],[[X,1]|R]) :- count(T,R).

?- count([1,1,1,2,2,2,3,1,1],R).
R = [[1, 3], [2, 3], [3, 1], [1, 2]].

这么容易(当然,假设X = [[1,3],[2,3], [1,3] [1,2]]这是一个错字。 ..)

答案 3 :(得分:0)

另一种解决方案(尾递归)是:

run_length_encode( Xs , Ys ) :- % to find the run length encoding of a list ,
  rle( Xs , 1 , Ys ) .          % - just invoke the helper

rle( []       , _ , []    ) .     % the run length encoding of the empty list is the empty list
rle( [A]      , N , [X:N] ) .     % A list of length 1 terminates the run: move the run length to the result
rle( [A,A|Xs] , N , Ys    ) :-    % otherwise, if the run is still going
  N1 is N+1 ,                     % - increment the count, 
  rle( [A|Xs] , N1 , Ys )         % - and recurse down
  .                               %
rle( [A,B|Xs] , N , [A:N|Ys] ) :- % otherwise, if the run has ended
  A \= B ,                        % - we have a break
  rle( [B|Xs] , 1 , Ys )          % - add the completed run length to the result and recurse down
  .                               %

答案 4 :(得分:0)

如果我们跳过使用"是"我们可以有一个解决方案:

precondition(Clause):-
  Clause =.. [_|ARGS],
  ( maplist(var,ARGS) -> true; Clause ).

count( [], [] ).

count( [X], [(X,1)] ) :- !.

count( [H|Q], [(H,1),(HR,NR)|QR] ) :-
   count( Q, [(HR,NR)|QR] ),
   H \= HR,
   !.

count( [H|Q], [(H,NR)|QR] ) :-
   precondition( succ(N,NR) ),
   count( Q, [(H,N)|QR] ), 
   succ(N,NR).

不仅允许通常的查询:

[debug]  ?- count([1,1,1,2,2,2,3,1,1],R).
R = [ (1, 3), (2, 3), (3, 1), (1, 2)].

但也反过来:

[debug]  ?- count(X, [ (1, 3), (2, 3), (3, 1), (1, 2)] ).
X = [1, 1, 1, 2, 2, 2, 3, 1, 1].