Prolog压缩列表

时间:2014-06-21 19:56:12

标签: list prolog

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

我编写了一个谓词,通过删除重复项来压缩列表。 因此,如果输入为[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).

5 个答案:

答案 0 :(得分:2)

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

现在,为了解决您的问题,这里是最简单的解决方案(已经是尾递归,因为@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).

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

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

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

答案 2 :(得分:2)

在这个答案中,我们使用 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].                           % succeeds deterministically

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

?- 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使我们能够...

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

答案 3 :(得分:2)

更容易:

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'列表(没有重复的列表),否则它是。

答案 4 :(得分:0)

compr([X1,X1|L1],[X1|L2]) :-
   compr([X1|L1],[X1|L2]),
   !.
compr([X1|L1],[X1|L2]) :-
   compr(L1,L2).
compr([],[]).