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

时间:2019-12-23 05:50:18

标签: list prolog grouping

我是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

先谢谢了。我正在尝试解决这些问题:

3 个答案:

答案 0 :(得分:3)

您可以通过简单的列表处理并使用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 ?-

答案 1 :(得分:2)

请注意,lurker's solution仍然存在一些性能问题。请参阅; false了解每种解决方案?这表明Prolog仍然保留一些内存(称为选择点-实际上可能甚至有几个这样的选择点)。但是,在许多情况下,不需要这样的选择点。这是一个解决该问题的解决方案(在Haskell的上下文中,名称group代替pack很常见)

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),这是一般不平等的情况

在后两种情况下,没有->,因为两者都可能是正确的。 由于维护这么多案件非常麻烦,因此有library(reif) 对于 SICStusSWI可以使内容更紧凑:

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 :(得分:1)

您得到的错误是因为如果=\=/2 number 不等于expr1,则expr2为真。相反,您可以使用\=\2来评估\+term1=term2==/2的值为term1 equivalent to term2,如果=:=/ number 等于{{1 }}。我在您的代码中发现的另一个错误是您没有清除中间列表。将类似元素列表添加到expr1列表后,必须刷新其中的值。我已使用剪切expr2来减少回溯。相反,如果编写互斥谓词,那就更好了。

我已经编辑了您的代码:

Sublists

输出:

!

希望这会有所帮助。