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

List Prolog中列表中连续相似元素的子列表,list,prolog,grouping,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

我对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).
以下是错误:

提前谢谢。我正在努力解决这些问题:

.
您得到的错误是,如果expr1的计算结果不等于expr2,则=\=/2为真。相反,您可以使用\=\2来计算\+term1=term2==/2的计算结果为等于term2的term1,如果expr1是等于expr2的数字,则=:=/为真。我在你的代码中发现的另一个错误是你没有清除中间列表。将相似元素列表添加到子列表后,必须刷新其中的值。我用了割伤!减少回溯。相反,如果编写互斥谓词,效果会更好

我已编辑了您的代码:

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),!.
输出:


希望这有帮助。

您得到的错误是,如果expr1的计算结果不等于expr2,则=\=/2为真。相反,您可以使用\=\2来计算\+term1=term2==/2的计算结果为等于term2的term1,如果expr1是等于expr2的数字,则=:=/为真。我在你的代码中发现的另一个错误是你没有清除中间列表。将相似元素列表添加到子列表后,必须刷新其中的值。我用了割伤!减少回溯。相反,如果编写互斥谓词,效果会更好

我已编辑了您的代码:

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),!.
输出:


希望这有帮助。

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

您可以通过简单的列表处理来解决此类问题,并使用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 ?-
请注意,仍然存在一些性能问题。看,;每个解决方案都为false?这表明Prolog仍然保留一些称为选择点的内存,实际上甚至可能有几个这样的选择点。然而,在许多情况下,不需要这样的选择点。这里有一个解决方案可以克服这个问题,在Haskell的上下文中,用名称组代替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).
注意E和F相等性的测试如何分为四种情况:

首先E\=F,这意味着两者完全不同

然后E==F,这意味着两者完全相同

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

difE,F,这是一般不等式的情况

对于最后两种情况,没有->因为两者都可能是真的。 由于维护如此多的案例相当麻烦,因此有libraryreif 对于 和 这样就可以更简洁地书写相同的内容:

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).
请注意,仍然存在一些性能问题。看,;每个解决方案都为false?这表明Prolog仍然保留一些称为选择点的内存,实际上甚至可能有几个这样的选择点。然而,在许多情况下,不需要这样的选择点。这里有一个解决方案可以克服这个问题,在Haskell的上下文中,用名称组代替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).
注意E和F相等性的测试如何分为四种情况:

首先E\=F,这意味着两者完全不同

然后E==F,这意味着两者完全相同

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

difE,F,这是一般不等式的情况

对于最后两种情况,没有->因为两者都可能是真的。 由于维护如此多的案例相当麻烦,因此有libraryreif 对于 和 这样就可以更简洁地书写相同的内容:

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).

谢谢你,伙计。它起作用了。我对prolog不太了解,我不明白什么是切割。你可以在这里探索更多关于切割的知识。这将是一个很好的练习,试图解决这个问题而不削减。切口经常被过度使用,如在本例中。它失去了一般性,代价是对一个逻辑问题获得了一个短期的解决方案。@Lower我使用了cut,这样后面的false就会被消除。有人告诉我,你应该努力消除答案后面的错误。@Ch3ster,是的,额外的错误是由于剩余的选择点。在这种情况下,解决方案可能是正确的,但这意味着解决方案不是完全确定的,也不是错误的。切割通常用作修复它的捷径,但切割消除了解决方案的通用性。在这种情况下,因为无论哪种方法都只有一个解决方案,所以它可以工作。谢谢你。它起作用了。我对prolog不太了解,我不明白什么是切割。你可以在这里探索更多关于切割的知识。这将是一个很好的练习,试图解决这个问题而不削减。切口经常被过度使用,如在本例中。它失去了一般性,代价是对一个逻辑问题获得了一个短期的解决方案。@Lower我使用了cut,这样后面的false就会被消除。有人告诉我
在中,您应该尝试消除答案后面的false。@Ch3ster,是的,额外的false是由于剩余的选择点。在这种情况下,解决方案可能是正确的,但这意味着解决方案不是完全确定的,也不是错误的。切割通常用作修复它的捷径,但切割消除了解决方案的通用性。在这种情况下,因为无论哪种方法都只有一个解决方案,所以它可以工作。你的答案应该被接受。希望他能看到这个漂亮的答案。@Ch3steR你的答案帮助Op理解=\=/2和\=/2之间的区别,所以这是一件好事!非常感谢,非常重要。但我太专注于OP的代码了,我只是编辑了他的代码。相反,我应该尝试从头开始编写代码。我想他会希望他的代码被编辑。@Ch3steR我自己已经做过很多次了。我通常喜欢帮助OP理解为什么他们的解决方案不起作用,这就是你的答案。我发布了一个不同的答案作为替代解决方案,但没有进入原始帖子的失败,因为你已经涵盖了这一点有时,发布的问题在其代码中还有其他更关键的问题,需要完全偏离原始答案。@潜伏者多亏了你,我今天在Prolog中学到了一些新东西。:'你的回答值得接受。希望他能看到这个漂亮的答案。@Ch3steR你的答案帮助Op理解=\=/2和\=/2之间的区别,所以这是一件好事!非常感谢,非常重要。但我太专注于OP的代码了,我只是编辑了他的代码。相反,我应该尝试从头开始编写代码。我想他会希望他的代码被编辑。@Ch3steR我自己已经做过很多次了。我通常喜欢帮助OP理解为什么他们的解决方案不起作用,这就是你的答案。我发布了一个不同的答案作为替代解决方案,但没有进入原始帖子的失败,因为你已经涵盖了这一点有时,发布的问题在其代码中还有其他更关键的问题,需要完全偏离原始答案。@潜伏者多亏了你,我今天在Prolog中学到了一些新东西。:'