【问题标题】:Prolog compressing listProlog压缩列表
【发布时间】:2016-11-10 22:33:34
【问题描述】:

我有一个奇怪的问题,我不知道如何解决。

我编写了一个谓词,它通过删除重复项来压缩列表。 所以如果输入是[a,a,a,a,b,c,c,a,a],输出应该是[a,b,c,a]。我的第一个代码有效,但项目顺序错误。所以我添加了一个append/3 目标,它完全停止了工作。

不知道为什么。我试图跟踪和调试,但不知道出了什么问题。

这是我的代码,它可以工作,但商品顺序错误:

p08([Z], X, [Z|X]).
p08([H1,H2|T], O, X) :-
    H1 \= H2,
    p08([H2|T], [H1|O], X).
p08([H1,H1|T], O, X) :-
    p08([H1|T], O, X).

这是较新的版本,但它根本不起作用:

p08([Z], X, [Z|X]).
p08([H1,H2|T], O, X) :-
    H1 \= H2,
    append(H1, O, N),
    p08([H2|T], N, X).
p08([H1,H1|T], O, X) :-
    p08([H1|T], O, X).

【问题讨论】:

  • 我建议使用dif/2 代替(\=)/2

标签: list prolog


【解决方案1】:

H1 不是列表,这就是append(H1, O, N) 失败的原因。 如果您将H1 更改为[H1],您实际上得到的解决方案与您的第一个解决方案相同。为了真正反转累加器中的列表,您应该更改前两个参数的顺序:append(O, [H1], N)。此外,您应该将第一条规则更改为与空列表 p08([], X, X) 匹配的规则(没有它,目标 p08([], [], Out) 将失败)。

现在,为了解决您的问题,这是最简单的解决方案(它已经是尾递归的,正如该答案的 cmets 中的 @false 所述,因此不需要累加器)

p([], []).                    % Rule for empty list
p([Head, Head|Rest], Out):-   % Ignore the Head if it unifies with the 2nd element
    !,                        
    p([Head|Rest], Out).
p([Head|Tail], [Head|Out]):-  % otherwise, Head must be part of the second list
    p(Tail, Out).

如果你想要一个和你相似的(使用蓄电池):

p08(List, Out):-p08(List, [], Out).

p08([], Acc, Acc).
p08([Head, Head|Rest], Acc, Out):-
    !,
    p08([Head|Rest], Acc, Out).
p08([Head|Tail], Acc, Out):-
    append(Acc, [Head], Acc2),
    p08(Tail, Acc2, Out).

【讨论】:

  • 您的第一个版本已经是尾递归的。它只会导致错误:p([a,Y],[a,b])。应该会成功。
  • 谢谢,我更正了我的说法。作者在他的原始解决方案中使用了统一而不是等价(并指定列表元素将是字符而不是未绑定的变量)。
  • @false,为什么第一个尾递归?有一个cons操作([Head|Out])只有在满足递归目标后才能完成。
  • 最后一个子句中与[Head|Out]的统一是在递归调用之前执行的。什么都没有留下(除了缺点[Head|Out],但无论如何都需要生产。
【解决方案2】:

简单明了:

list_withoutAdjacentDuplicates([],[]).
list_withoutAdjacentDuplicates([X],[X]).
list_withoutAdjacentDuplicates([X,X|Xs],Ys) :-
   list_withoutAdjacentDuplicates([X|Xs],Ys).
list_withoutAdjacentDuplicates([X1,X2|Xs],[X1|Ys]) :-
   dif(X1,X2),
   list_withoutAdjacentDuplicates([X2|Xs],Ys).

示例查询:

?- list_withoutAdjacentDuplicates([a,a,a,a,b,c,c,a,a],Xs).
Xs = [a,b,c,a] ;         % succeeds, but leaves useless choicepoint(s) behind
false

编辑 2015-06-03

以下代码基于@false 的if_/3reified term equality (=)/3,这---结合第一个参数索引---帮助我们避免上述无用选择点的创建。

list_without_adjacent_duplicates([],[]).
list_without_adjacent_duplicates([X|Xs],Ys) :-
   list_prev_wo_adj_dups(Xs,X,Ys).

list_prev_wo_adj_dups([],X,[X]).
list_prev_wo_adj_dups([X1|Xs],X0,Ys1) :-
   if_(X0 = X1, Ys1 = Ys0, Ys1 = [X0|Ys0]),
   list_prev_wo_adj_dups(Xs,X1,Ys0).

让我们看看它的实际效果!

?- list_without_adjacent_duplicates([a,a,a,a,b,c,c,a,a],Xs).
Xs = [a,b,c,a].          % succeeds deterministically

【讨论】:

    【解决方案3】:

    在这个答案中,我们使用 foldl/4Prolog lambdas.

    :- use_module(library(apply)).
    :- use_module(library(lambda)).
    

    我们基于if_/3(=)/3定义逻辑纯谓词list_adj_dif/2

    list_adj_dif([],[]).
    list_adj_dif([X|Xs],Ys) :-
       foldl(\E^(E0-Es0)^(E-Es)^if_(E=E0,Es0=Es,Es0=[E0|Es]),Xs,X-Ys,E1-[E1]).
    

    让我们运行 OP 给出的查询!

    ?- list_adj_dif([a,a,a,a,b,c,c,a,a ],Xs)。 Xs = [a,b,c,a]。 % 确定性地成功

    更一般的查询怎么样?我们是否得到了我们期望的所有解决方案?

    ?- list_adj_dif([A,B,C],Xs).
          A=B ,     B=C , Xs = [C]
    ;     A=B , dif(B,C), Xs = [B,C]
    ; dif(A,B),     B=C , Xs = [A,C]
    ; dif(A,B), dif(B,C), Xs = [A,B,C].
    

    是的,我们做到了!所以... 底线是?

    像以前一样,单调 if-then-else 构造 if_/3 使我们能够...

    • ...,保留,...
    • ...,防止创建无用的选择点(在许多情况下),...
    • ...,并保持单调 - 以免我们以效率的名义失去解决方案。

    【讨论】:

      【解决方案4】:

      更容易:

      compress([X],[X]).
      
      compress([X,Y|Zs],Ls):-
             X = Y,
             compress([Y|Zs],Ls).
      
      compress([X,Y|Zs],[X|Ls]):-
             X \= Y,
             compress([Y|Zs],Ls).
      

      代码递归地工作,它深入到基本情况,列表只包含一个元素,然后它出现,如果找到的元素等于他右边的那个,那么这个元素不会添加到'Ls' 列表(没有重复的列表),否则就是。

      【讨论】:

        【解决方案5】:
        compr([X1,X1|L1],[X1|L2]) :-
           compr([X1|L1],[X1|L2]),
           !.
        compr([X1|L1],[X1|L2]) :-
           compr(L1,L2).
        compr([],[]).
        

        【讨论】:

        • 由于您这里有几行代码,您能否描述一下它的工作原理和问题的答案,以便将来的访问者更容易理解您的答案?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-06
        • 2016-01-23
        • 1970-01-01
        • 2010-11-07
        • 2018-06-03
        • 2012-09-13
        相关资源
        最近更新 更多