以紧凑形式实现列表的赋值

时间:2015-11-08 21:53:16

标签: list prolog

我在课程作业中有一个问题。

  

考虑[a,a,a,b,b,c,a,a,a,a]形式的重复列表及其紧凑形式,定义为夫妻名单[[a,3],[b,2],[c,1],[a,4]]

     

如果给定列表compress/2compress(+L1, ?L2)是其紧凑形式,则定义谓词L1以满足L2

到目前为止,我已经提出了以下代码:

compress(X,[[X,1]]).
compress([H1,H2|T1],[[H1,C]|T2]):-
   H1 = H2,
   compress(T1,T2),
   C is R + 1.

我不确定我是否正确行事。请有人指出正确的方向。

3 个答案:

答案 0 :(得分:3)

以下是一些让您入门的建议。

由于您的结果有计数器,因此您需要保留重复元素的运行计数。所以,请考虑一个包含计数器的辅助谓词,这是在Prolog中处理它的典型方法。这种计数器的使用通常称为累加器

compress(L, C) :-
    compress(L, 1, C).   % Start counter at 1

现在您需要考虑几种不同的情况:

compress([], _, []).                 % This is an easy one!

这表示如果我压缩一个空列表,我会得到一个空列表。

compress([H], Count, [[H,Count]]).   % This is an easy one!

这个说如果我压缩一个元素的列表并且我当前的运行计数是Count,那么结果是[[H, Count]]

compress([H, H|T], Count, TC) :-
    ...

这是我有一个运行计数并且元素仍在重复的情况。结果将是一个列表TC,但我还不知道它的样子,因为我们仍处于重复循环中,需要通过递归来确定。这个谓词应该是什么样的?在您的示例中,当前两个元素相同时,您在结果中包含了一个计数,这不是包含计数的正确时间(参见下面的条款)。

compress([H1, H2|T], Count, [[H1,Count]|TC]) :-
    dif(H1, H2),
    ...

这是我有一个运行计数并且重复停在H1的情况。由于当前周期的重复以H1结尾,因此我们知道结果看起来像[[H1, Count]|TC],因为H1已重复Count次。我们还没有通过递归确定列表TC的其余部分。这个谓词实现应该是什么样的?

还有其他方法可以执行上述逻辑(例如,使用->;构造等),但这样可以保持简单。

尝试将这些视为规则,其中谓词子句的头部是断言,如果子句的以下元素为真,则该断言将为真。并递归思考。

<小时/> 作为事后的想法,通过使用结果来携带累加器,可以在没有单独的累加器的情况下完成:

compress([], []).
compress([H], [[H,1]]).
compress([H1,H2|T], [[H1,1]|R]) :-
    dif(H1, H2),
    compress(...).                 % left as an exercise
compress([H,H|T], [[H,N]|R]) :-
    N #= N1 + 1,
    compress(...).                 % left as an exercise

答案 1 :(得分:1)

我选择这样做:

?- compress([a,a,a,b,b,c,a,a,a,a],L), write(L), nl, fail.

compress(X,R) :-
    enumerate(X,Y),
    collapse(Y,R).

enumerate([],[]).
enumerate([H|T],[[H,1]|R]) :- enumerate(T,R).

collapse([],[]).
collapse([X],[X]).
collapse([[X,N1],[X,N2]|T],R) :- N is N1 + N2, collapse([[X,N]|T],R).
collapse([[X,N1],[Y,N2]|T],[[X,N1]|R]) :- X \= Y, collapse([[Y,N2]|T],R).

enumerate谓词只是将[a, a, a, b, b, c, a, a, a, a]映射到[[a, 1], [a, 1], [a, 1], [b, 1], [b, 1], [c, 1], [a, 1], [a, 1], [a, 1], [a, 1]]

然后我通过匹配列表的前两个头来collapse这个列表 - 如果他们统一添加值并再次尝试collapse。如果他们不统一,则从列表中弹出一个元素并再次collapse。否则有两种基本情况 - 空列表和包含一个元素的列表。

结果是:[[a, 3], [b, 2], [c, 1], [a, 4]]

答案 2 :(得分:1)

以下是使用splitlistIfAdj/3执行此操作的方法 与dif/3结合使用。

首先,确定相等的相邻列表项的运行:

?- splitlistIfAdj(dif, [a,a,a,b,b,c,a,a,a,a], Xss).
Xss = [[a,a,a],[b,b],[c],[a,a,a,a]].

然后,使用maplist/3length/2

将每次运行映射到其长度
?- maplist(length, [[a,a,a],[b,b],[c],[a,a,a,a]], Ls).
Ls = [3,2,1,4].

差不多完成了!让我们使用Prolog lambdas

将它们放在一起
:- use_module(library(lambda)).

list_compressed(Xs, Yss) :-
   splitlistIfAdj(dif, Xs, Xss),
   maplist(\Es^(E-N)^(Es=[E|_],length(Es,N)), Xss, Yss).

示例查询:

?- list_compressed([a,a,a,b,b,c,a,a,a,a], Xss).
Xss = [a-3,b-2,c-1,a-4].