如何删除从Prolog的列表中最后一个元素?(How to delete the last elem

2019-08-31 22:54发布

我在下面的情况:我有一个名单,我就从它只有最后一个元素删除。

我已经实现了以下规则(不正常工作):

deleteLastElement([Only],WithoutLast) :-
    !,
    delete([Only],Only,WithoutLast).
deleteLastElement([_|Tail],WithoutLast) :-
    !,
    deleteLastElement(Tail,WithoutLast).

问题是,当我把它称为,列表中的所有元素都将被删除,其实如果我执行下面的语句我获得:

[debug]  ?- deleteLastElement([a,b,c], List).
List = [].

望着跟踪我认为这是明确这个问题的原因:

[trace]  ?- deleteLastElement([a,b], List).
   Call: (7) deleteLastElement([a, b], _G396) ? creep
   Call: (8) deleteLastElement([b], _G396) ? creep
   Call: (9) lists:delete([b], b, _G396) ? creep
   Exit: (9) lists:delete([b], b, []) ? creep
   Exit: (8) deleteLastElement([b], []) ? creep
   Exit: (7) deleteLastElement([a, b], []) ? creep
List = [].

当达到基础的情况下,WithoutLast列表被统一为空列表 []并执行时的回溯WithoutLast仍然保持在空列表。

这个不好。

我想实现它执行以下操作:

  1. 算上元素在列表中的号码之前调用删除最后一个元素的谓词。
  2. 通过递归迭代和递减每次元件的数目的值
  3. 如果这是真的,元素的数量为0则表示,这是最后一个元素,所以我从原来的列表中删除

但是,这在我看来,不清晰,不那么好,如果有此问题的声明很好地解决我会知道的。

Answer 1:

为了防止无用choicepoints的创建,使用落后的,从第一个参数的索引中获益:

list_butlast([X|Xs], Ys) :-                 % use auxiliary predicate ...
   list_butlast_prev(Xs, Ys, X).            % ... which lags behind by one item

list_butlast_prev([], [], _).
list_butlast_prev([X1|Xs], [X0|Ys], X0) :-  
   list_butlast_prev(Xs, Ys, X1).           % lag behind by one

示例查询:

?- list_butlast([], Xs).
false.

?- list_butlast([1], Xs).
Xs = [].                                    % succeeds deterministically

?- list_butlast([1,2], Xs).
Xs = [1].                                   % succeeds deterministically

?- list_butlast([1,2,3], Xs).
Xs = [1,2].                                 % succeeds deterministically

如何在另一个方向?

?- list_butlast(Xs, []).
Xs = [_A].

?- list_butlast(Xs, [1,2,3]).
Xs = [1,2,3,_A].

什么最一般的查询?

?- list_butlast(Xs, Ys).
   Xs = [_A]            , Ys = []
;  Xs = [_A,_B]         , Ys = [_A]
;  Xs = [_A,_B,_C]      , Ys = [_A,_B]
;  Xs = [_A,_B,_C,_D]   , Ys = [_A,_B,_C]
;  Xs = [_A,_B,_C,_D,_E], Ys = [_A,_B,_C,_D]
⋯


Answer 2:

我觉得你的分析有点过于复杂。 让我们从基础开始的情况下:

without_last([_], []).

当你在最后一个元素,结果应该是空列表。

因此,电感情况一定是这样的,我们是不是在最后一个元素。 在我具有连接到一个任意长的列表中的某些元件的情况下,没有最后元素名单只是不与在前面所述当前元素的最后一个元素的列表的尾部。 要么:

without_last([X|Xs], [X|WithoutLast]) :- 
    without_last(Xs, WithoutLast).

这部作品在每一个方向。

?- without_last([1,2,3,4], X).
X = [1, 2, 3] ;
false.

?- without_last([1,2], X).
X = [1] .

?- without_last([1], X).
X = [] ;
false.

?- without_last([], X).
false.

?- without_last(X, [1,2,3]).
X = [1, 2, 3, _G294].

?- without_last([1,2,3,4], [1,2,3]).
true.

?- without_last([1,2,3,X], [1,2,3]).
true.


Answer 3:

如果你开发一个递归过程,其经过输入列表中的每一个元素,当你找到的最后一个元素统一与空列表结果列表中你的基本情况将停止。 然后,从递归调用返回你刚才所有其他项目添加到结果列表:

如果不使用切:

deleteLastElement([_], []).
deleteLastElement([Head, Next|Tail], [Head|NTail]):-
  deleteLastElement([Next|Tail], NTail).

第一条款(基础情况)相结合用空列表中的第二个参数时,只有一个在第一个参数列表元素。

第二条指出,当第一个参数是至少有两个元素的列表,那么你递归调用本身(不包括头),一个头添加到由调用返回的第二个参数。

其实你并不需要作出明确的名单需要有至少两种元素的第二个条款中,

deleteLastElement([Head|Tail], [Head|NTail]):-
  deleteLastElement(Tail, NTail).

而且,当然,你也可以使用了append/3从列表中删除最后一个项目:

append(WithoutLast, [_], List).


Answer 4:

@重复的实现无疑是最有效的一个与当前的Prolog的处理器,还是我喜欢用DCG中用于此目的 - 偷偷希望有一天实现技术将是不够好,具有可比性(空间)的效率运行此。

list_butlast(Xs, Ys) :-
   phrase( ( seq(Ys), [_] ), Xs).

seq([]) -->
   [].
seq([E|Es]) -->
   [E],
   seq(Es).


文章来源: How to delete the last element from a list in Prolog?
标签: list prolog