繁体   English   中英

Prolog 列表中连续相似元素的子列表

[英]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).

请注意EF相等性的测试如何分为四种情况:

  1. 首先E \\= F这意味着两者肯定不同。

  2. 然后E == F这意味着两者绝对相同。

  3. 然后E = F这是相等的一般情况,并且

  4. dif(E, F)这是一般不等式的情况

对于最后两种情况,没有->因为两者都可能是真的。 由于维护这么多案例非常麻烦,因此SICStusSWI 的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM