我在课程作业中有一个问题。
考虑
[a,a,a,b,b,c,a,a,a,a]
形式的重复列表及其紧凑形式,定义为夫妻名单[[a,3],[b,2],[c,1],[a,4]]
。如果给定列表
compress/2
,compress(+L1, ?L2)
是其紧凑形式,则定义谓词L1
以满足L2
。
到目前为止,我已经提出了以下代码:
compress(X,[[X,1]]).
compress([H1,H2|T1],[[H1,C]|T2]):-
H1 = H2,
compress(T1,T2),
C is R + 1.
我不确定我是否正确行事。请有人指出正确的方向。
答案 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(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].