繁体   English   中英

从 Prolog 中的列表中删除连续元素

[英]Removing consecutive elements from a list in Prolog

到目前为止,我尝试了三个单独的函数,其中一个是第一个调用 function,另外两个决定是否将 append 元素传递给我们的结果列表,如果它与列表的头部不匹配。 递归使我感到困惑,因为它使许多其他人感到困惑,所以在这里的某个地方我有一个无限循环,导致堆栈溢出。 但是我不确定很多 prolog 概念(或语法),所以我很困惑我哪里出错了。 感谢您的帮助!

append( [X | Y], Z, [X | W]) :- append( Y, Z, W). 

remove([], []).

remove([H|T], X) :-
    append(X, [H], X),
    remove(T, H, X),
    !.

remove([Y|T], Y, X):-
    remove(T, Y, X),
    !.

remove([H|T], Y, X):-
    append(X,[H], X),
    remove(T,Y,X),
    !.```

嗯...首先, Prolog 没有“功能”:它有predicates

如果我理解您的问题陈述,您想“从列表中删除连续元素”,我理解这意味着“将相同元素的运行折叠为单个值”,因此列表如下:

[a,b,b,b,,c,c,d,e,e,e,e]

减少到

[a,b,c,d,e]

假设是这种情况,您不需要(或不想要) append/3 总体方案是

  • 递归到列表的末尾,然后
  • 当您弹出调用堆栈时,您根据返回列表的头部重复添加或省略当前项

像这样:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .

try_add/3负责决定是否在返回列表中添加/添加一个项目。 它也是微不足道的:

  • 如果返回的列表为空,则在其前面添加候选X
  • 如果返回列表非空,则用返回列表的头部测试候选X
    • 如果它们是可统一的,则省略候选X
    • 否则,将候选X添加到返回的列表中
try_add( X , []     ,      [X] ) .
try_add( X , [T|Ts] ,   [T|Ts] ) :- X  = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.

将所有内容放在一起,您会得到:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs,Ts), try_add(X,Ts,Ys) .

try_add( X , []     ,      [X] ) .
try_add( X , [T|Ts] ,   [T|Ts] ) :- X  = T.
try_add( X , [T|Ts] , [X,T|Ts] ) :- X \= T.

这在 O(n) 时间和空间中运行。 它的缺点是它不是尾递归的,这意味着给定一个足够长的列表,它会使你的程序因堆栈溢出而崩溃。

另一种尾递归方法——在 O(n) 时间和 O(1) 空间中运行——是这样的:

remove( []     , [] ) .
remove( [X|Xs] , Ys ) :- remove(Xs, [X], Ts ), reverse(Ts,Ys) .

remove( []     , Ys     , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X  = T , remove( Xs ,  [X|Ts] , Ys ) .
remove( [X|Xs] , [T|Ts] , Ys ) :- X \= T , remove( Xs ,[X,T|Ts] , Ys ) .

它的缺点是它以相反的顺序构建返回列表,因此需要通过reverse/2进行另一次遍历才能将事物以正确的顺序放回原处。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM