[英]Pack consecutive duplicates of list elements into sublists in Prolog
我有一个问题,回答P-99问题9的答案:九十九个Prolog问题 :
将列表元素的连续重复包装到子列表中。 如果列表包含重复元素,则应将它们放在单独的子列表中。
带有预期结果的示例查询:
?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]].
我设法在子列表中打包元素,但我不知道如何返回答案。
这是我的代码:
pack(X,Y) :- pack(X,[],Y).
pack([H,H|T],Acc,X) :- pack([H|T],[H|Acc],X).
pack([H,H1|T], Acc, X) :-
H\=H1,
Acc1=[H|Acc],
append(X, [Acc1], X1),
pack([H1|T],[],X1).
pack([H], Acc, X) :-
Acc1=[H|Acc],
append(X, [Acc1], X1).
这是在跟踪模式下运行的查询:
?- trace, pack([a,a,a,a,b,c,c],X).
Call: (6) pack([a, a, a, a, b, c, c], _G986) ? creep
Call: (7) pack([a, a, a, a, b, c, c], [], _G986) ? creep
Call: (8) pack([a, a, a, b, c, c], [a], _G986) ? creep
Call: (9) pack([a, a, b, c, c], [a, a], _G986) ? creep
Call: (10) pack([a, b, c, c], [a, a, a], _G986) ? creep
Call: (11) a\=b ? creep
Exit: (11) a\=b ? creep
Call: (11) _G1100=[a, a, a, a] ? creep
Exit: (11) [a, a, a, a]=[a, a, a, a] ? creep
Call: (11) lists:append(_G986, [[a, a, a, a]], _G1105) ? creep
Exit: (11) lists:append([], [[a, a, a, a]], [[a, a, a, a]]) ? creep
Call: (11) pack([b, c, c], [], [[a, a, a, a]]) ? creep
Call: (12) b\=c ? creep
Exit: (12) b\=c ? creep
Call: (12) _G1109=[b] ? creep
Exit: (12) [b]=[b] ? creep
Call: (12) lists:append([[a, a, a, a]], [[b]], _G1114) ? creep
Exit: (12) lists:append([[a, a, a, a]], [[b]], [[a, a, a, a], [b]]) ? creep
Call: (12) pack([c, c], [], [[a, a, a, a], [b]]) ? creep
Call: (13) pack([c], [c], [[a, a, a, a], [b]]) ? creep
Call: (14) _G1127=[c, c] ? creep
Exit: (14) [c, c]=[c, c] ? creep
Call: (14) lists:append([[a, a, a, a], [b]], [[c, c]], _G1132) ? creep
Exit: (14) lists:append([[a, a, a, a], [b]], [[c, c]], [[a, a, a, a], [b], [c, c]]) ? creep
Exit: (13) pack([c], [c], [[a, a, a, a], [b]]) ? creep
Exit: (12) pack([c, c], [], [[a, a, a, a], [b]]) ? creep
Exit: (11) pack([b, c, c], [], [[a, a, a, a]]) ? creep
Exit: (10) pack([a, b, c, c], [a, a, a], []) ? creep
Exit: (9) pack([a, a, b, c, c], [a, a], []) ? creep
Exit: (8) pack([a, a, a, b, c, c], [a], []) ? creep
Exit: (7) pack([a, a, a, a, b, c, c], [], []) ? creep
Exit: (6) pack([a, a, a, a, b, c, c], []) ? creep
X = [] .
我想在最后一条规则的末尾应该有一些额外的行以某种方式将结果绑定到输入但我不知道如何去做。
首先要做的事情是:你有一个关于X1的单例变量警告:
pack([H], Acc, X) :-
Acc1=[H|Acc],
append(X, [Acc1], X1).
整个规则简化为:
pack([H], Acc, X) :- append(X, [[H|Acc]], _).
那肯定不是你想要的,但看看你在这里得到的东西,我不确定你想要什么。 首先,我不会使用append/3
解决问题。 你的解决方案实际上生成了不同值的列表,这告诉我某处发生了非常严重的失火。
?- pack([a, a, a, a, b, c, c], X).
X = [] ;
X = [_G704] ;
X = [_G704, _G710] ;
X = [_G704, _G710, _G716] ;
X = [_G704, _G710, _G716, _G722] a
我希望我能看到问题,因为在跟踪中我看到你正确地构建了结果。 有更多洞察力的人可能会为您的错字提供解决方案。
无论如何,这就是我提出的:
pack([X|Unpacked], Packed) :- pack(Unpacked, [[X]], Packed).
pack([H|T], [[H|Acc]|Rest], Packed) :- pack(T, [[H,H|Acc]|Rest], Packed).
pack([X|T], [[Y|Acc]|Rest], Packed) :-
X \= Y,
pack(T, [[X],[Y|Acc]|Rest], Packed).
pack([], RPacked, Packed) :- reverse(RPacked, Packed).
事实上,差异列表解决方案允许在不使用append/3
或最后使用reverse/2
情况下进行前置,但我的后袋中没有。
我认为这个会奏效。 我使用“累加器”来收集重复的成员子列表。
pack([], []).
pack(L, Pack) :-
pack(L, [], Pack).
pack([X], FrontPack, [[X|FrontPack]]).
pack([X,X|T], FrontPack, Pack) :-
pack([X|T], [X|FrontPack], Pack).
pack([X,Y|T], FrontPack, [[X|FrontPack]|Pack]) :-
X \= Y,
pack([Y|T], [], Pack).
结果:
| ?- pack([a],X).
X = [[a]] ? ;
no.
| ?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]] ? ;
no
| ?-
这是使代码工作所需的最小修改:添加一个'仅返回'变量,以'emerge'从内部工作追加到顶级的结果:
pack(X,Y) :- pack(X,[],_,Y).
pack([H,H|T],Acc,X,R) :- pack([H|T],[H|Acc],X,R).
pack([H,H1|T], Acc, X,R) :-
H\=H1,
Acc1=[H|Acc],
append(X, [Acc1], X1),
pack([H1|T],[],X1,R).
pack([H], Acc, X,R) :-
Acc1=[H|Acc],
append(X, [Acc1], X1),
R = X1.
测试:
?- pack([a,a,a,a,b,c,c],X).
X = [[a, a, a, a], [b], [c, c]] .
正如你所看到的,有很多可用的替代算法:这是我的,我试图尽可能简化:
pack(L, P) :- pack(L, [], P).
pack([X|Xs], R, P) :-
add_pack(X, R, R1), pack(Xs, R1, P).
pack([], R, P) :-
reverse(R, P).
add_pack(X, [[X|Xs]|R], [[X,X|Xs]|R]).
add_pack(X, [R|Rs], [[X],R|Rs]).
add_pack(X, [], [[X]]).
它的行为与'天真插入排序'最相似:取前面元素并将其放在正确的位置。 为了避免附加元素,我使用累加器,在最后反转(这里的大多数其他答案)。
编辑我想,阅读其他答案,其他人(像我一样)发现你的代码很难理解。 原因可能是您正在混合“输入/输出”参数。 作为一种风格选择,Prologgers通常坚持'先输入,输出最后'。 这并不总是有意义的(毕竟,Prolog是关于关系,而不是函数),但是通常是一个有用的,简单的技术。
HTH
以下是如何以逻辑上纯粹的方式实现它:将元谓词splitlistIfAdj/3
与dif/3
结合使用,这是prolog-dif的一个具体变体。 我们现在就做一些问题吧!
?- Xs = [a], splitlistIfAdj(dif,Xs,Pss).
Xs = [ a ],
Pss = [[a]]. % succeeds deterministically
?- Xs = [a,a,a,a,b,c,c], splitlistIfAdj(dif,Xs,Pss).
Xs = [ a,a,a,a, b, c,c ],
Pss = [[a,a,a,a],[b],[c,c]]. % succeeds deterministically
?- Xs = [a,a,a,a,b,c,c,a,a,d,e,e,e,e], splitlistIfAdj(dif,Xs,Pss).
Xs = [ a,a,a,a, b, c,c, a,a, d, e,e,e,e ],
Pss = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]].% succeeds deterministically
与不纯的代码不同,实现是单调的 ,可以与非基础术语一起使用:
?- Xs = [A,B], splitlistIfAdj(dif,Xs,Pss), A=1, B=2. Xs = [1,2], A = 1, B = 2, Pss = [[1],[2]]. ?- Xs = [A,B], A=1, B=2, splitlistIfAdj(dif,Xs,Pss). % logically equivalent Xs = [1,2], A = 1, B = 2, Pss = [[1],[2]].
请注意,像下面这样的更一般的查询也给出了逻辑上合理的答案 :
?- Xs = [A,B,C,D], splitlistIfAdj(dif,Xs,Pss).
Xs = [D,D,D,D], Pss = [[D,D,D,D]], A=B , B=C , C=D ;
Xs = [C,C,C,D], Pss = [[C,C,C],[D]], A=B , B=C , dif(C,D) ;
Xs = [B,B,D,D], Pss = [[B,B],[D,D]], A=B , dif(B,C), C=D ;
Xs = [B,B,C,D], Pss = [[B,B],[C],[D]], A=B , dif(B,C), dif(C,D) ;
Xs = [A,D,D,D], Pss = [[A],[D,D,D]], dif(A,B), B=C , C=D ;
Xs = [A,C,C,D], Pss = [[A],[C,C],[D]], dif(A,B), B=C , dif(C,D) ;
Xs = [A,B,D,D], Pss = [[A],[B],[D,D]], dif(A,B), dif(B,C), C=D ;
Xs = [A,B,C,D], Pss = [[A],[B],[C],[D]], dif(A,B), dif(B,C), dif(C,D).
如果你使用SWI-Prolog,带模块(library(lambda))和foldl,你可以写:
:- use_module(library(lambda)).
pack(L, PL) :-
L = [A | B],
foldl(\X^Y^Z^(Y = [LY | RY],
( member(X, LY)
-> Z = [[X | LY]|RY]
; Z = [[X]| [LY | RY]])),
B, [[A]], RPL),
reverse(RPL, PL).
模块lambda.pl可以在那里找到: http : //www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
我认为这样的事情应该有效:
%=============================
% pack/2: The public interface
%=============================
pack( [] , [] ) . % packing an empty list yields the empty list
pack( [X|Xs] , [Y|Ys] ) :- % packing a non-empty list consists of
construct_run( Xs , [X] , Run , Tail ) , % - building a run of length 1 or more from the prefix of the list
simplify_run( Run , Y ) , % - simplfying it for the special case of a run of length 1
pack( Tail , Ys ) % - and then recursively packing whatever is left.
. % Easy!
%--------------------------
% private helper predicates
%--------------------------
%
% construct_run/4
%
construct_run( [] , Run , Run , [] ) . % the run is complete if the source list is exhausted
construct_run( [X|Xs] , [R|Rs] , [R|Rs] , [X|Xs] ) :- % the run is complete if the head of the source list differs
T \= R % from what's already in the run
. %
construct_run( [X|Xs] , [R|Rs] , Run , Tail ) : % otherwise,
T = R , % - if the head of the source list matches what's already in the run,
construct_run( Xs , [T,R|Rs] , Run , Tail ) % - we prepend it to the run and recurse down.
. %
%
% simplify_run/2 - deal with the special case of run length 1
%
simplify_run( [A] , A ) . % run length = 1
simplify_run( [A,B|C] , [A,B|C] ) . % run length > 1
class find:
def enter_list(self): #function defined to create comma seperated list
input_element=raw_input('Enter comma seperated elements -')
mylist=[ x for x in input_element.split(',')]
return mylist
def get_sublist(self,x):
prev="" #prev flag generated to check previous element match or not
return_list=[] #return_list created to store final output
flag=0 #as first element dont have prev element to check for match
for i in range(len(x)):
if x[i]!=prev: #if no prev match then create new sublist
if flag==0: #for first element
sorted_list=[] #sorted_list is used to store sublist
sorted_list.append(x[i])
prev=x[i]
else:
return_list.append(sorted_list)
sorted_list=[]
sorted_list.append(x[i])
prev=x[i]
elif x[i]==prev: #if match with prev append to sublist
sorted_list.append(x[i])
prev=x[i]
flag=1
if i==len(x)-1: #block to append last sublist to list
return_list.append(sorted_list)
return return_list
a=find()
create_list=a.enter_list()
print "Entered list : ",create_list
print a.get_sublist(create_list) #print output by providing normal list
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.