[英]Sublists of consecutive similar elements from a list in Prolog
我是 Prolog 的新手,正在尝试回答这个问题。 我们有一个清单
List = [a,a,a,a,b,c,c,a,a,d,e,e,e,e]
我想把它打包成相似元素的子列表。
Pack( [a,a,a,a,b,c,c,a,a,d,e,e,e,e], Sublists)
应该给
Sublists = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]
这是我迄今为止尝试过的:
pack([],[],[]).
pack([H],[H],[H]).
pack([H,H1|T],Z,X):- H==H1 , append([H],Z,Z1) , pack([H1|T],Z1,X).
pack([H,H1|T],Z,X):- H=\=H1 , append([H],Z,Z1) ,
append(Z1,X,Xs) , pack([H1|T],Z1,Xs).
下面是错误:
Arithmetic: `a/0' is not a function In: [4] a=\\=b [3] pack([a,b|...],[a,a],_1608) at line 13 [2] pack([a,a|...],[a],_1688) at line 13 [1] pack([a,a|...],[],_1762) at line 13
提前致谢。 我正在尝试解决这些问题:
您可以通过简单的列表处理并使用 SWI Prolog 的dif/2
来提供通用解决方案来解决此类问题:
pack([], []). % packing empty is empty
pack([X], [[X]]). % packing a single element
pack([X,X|T], [[X|PH]|PT]):- % rule for packing when next two terms are the same
pack([X|T], [PH|PT]).
pack([X,Y|T], [[X]|PT]):- % rule for different term
dif(X, Y),
pack([Y|T], PT).
2 ?- pack([a,a,a,a,b,c,c,a,a,d,e,e], L).
L = [[a, a, a, a], [b], [c, c], [a, a], [d], [e, e]] ;
false.
3 ?- pack(L, [[a,a,a], [b,b], [c]]).
L = [a, a, a, b, b, c] ;
false.
4 ?-
请注意, lurker 的解决方案仍然存在一些性能问题。 见; false
每个解决方案都是; false
的? 这表明 Prolog 仍然保留一些内存(称为选择点 - 实际上甚至可能有几个这样的选择点)。 然而,对于许多情况,不需要这样的选择点。 这是克服该问题的解决方案(名称group
代替pack
在 Haskell 的上下文中很常见)
group([], []).
group([E|Es], [[E|Gs]|Gss]) :-
igroup(Es, E, Gs, Gss).
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
( E\=F
-> Gs1=[], Gss1=[[E|Gs2]|Gss2]
; E==F
-> Gs1=[E|Gs2], Gss1=Gss2
; E=F,
Gs1=[E|Gs2], Gss1=Gss2
; dif(E, F),
Gs1=[], Gss1=[[E|Gs2]|Gss2]
),
igroup(Es, E, Gs2, Gss2).
请注意E
和F
相等性的测试如何分为四种情况:
首先E \\= F
这意味着两者肯定不同。
然后E == F
这意味着两者绝对相同。
然后E = F
这是相等的一般情况,并且
dif(E, F)
这是一般不等式的情况
对于最后两种情况,没有->
因为两者都可能是真的。 由于维护这么多案例非常麻烦,因此SICStus和SWI 的library(reif)
允许更紧凑地编写相同的代码:
igroup([], _, [], []).
igroup([E|Es], F, Gs1, Gss1) :-
if_(E = F
, ( Gs1 = [E|Gs2], Gss1 = Gss2 )
, ( Gs1 = [], Gss1 = [[E|Gs2]| Gss2] )),
igroup(Es, E, Gs2, Gss2).
你有这个错误是因为=\\=/2
为真,如果expr1
是计算为一个数字不等于expr2
。 相反,您可以使用\\=\\2
来评估\\+term1=term2
。 ==/2
计算结果为term1 equivalent to term2
,如果expr1
是一个等于expr2
的数字,则=:=/
为真。 我在您的代码中发现的另一个错误是您没有清除中间列表。 在将相似元素列表添加到Sublists
列表列表后,您必须刷新其中的值。 我用过切!
以减少回溯。 相反,如果您编写互斥谓词,那就更好了。
我已经编辑了您的代码:
pack1([],[],[]).
pack1([H],L,[Z]):- append([H],L,Z),!.
pack1([H,H1|T],Z,X):- H == H1 , append([H],Z,Z1) , pack1([H1|T],Z1,X),!.
pack1([H,H1|T],Z,[Z1|Zs]):- H\=H1 ,append([H],Z,Z1) ,pack1([H1|T],[],Zs),!.
输出:
?-pack1([a,a,a,a,b,c,c,a,a,d,e,e,e,e],[],Z).
Z=[[a, a, a, a], [b], [c, c], [a, a], [d], [e, e, e, e]]
?-pack1([a,a,a,a,b,c,1,c,a,a,d,e,e,e,e],[],Z).
Z= [[a, a, a, a], [b], [c], [1], [c], [a, a], [d], [e, e, e, e]]
?-pack1([],[],Z).
Z= []
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.