简体   繁体   English

哪个是“takeEnd”的更高效版本 function

[英]Which is a more efficient version of "takeEnd" function

I am new to PureScript so I am re-creating some basic functions, and I wanted to recreate "takeEnd" function which takes specified number of elements from the end of the list.我是 PureScript 的新手,所以我正在重新创建一些基本函数,我想重新创建“takeEnd”function,它从列表末尾获取指定数量的元素。

Here is solution I wrote:这是我写的解决方案:

takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n l = go n Nil $ reverse l where
    go _ new Nil = new
    go 0 new _ = new
    go n new  (x : xs) = go (n - 1) (x : new) xs

And here is a solution I found in a book:这是我在一本书中找到的解决方案:

takeEnd :: forall a. Int -> List a -> List a
takeEnd _ Nil = Nil
takeEnd n  = go >>> snd where
    go Nil = Tuple 0 Nil
    go (x : xs) = go xs
        # \(Tuple c nl) -> Tuple (c + 1) $ if c < n then x : nl else nl

I am interested in which version is more efficient?我对哪个版本更有效感兴趣? If I am not mistaken I believe also that second version is not tail optimized如果我没记错的话,我也相信第二个版本没有尾部优化

The second solution does a single traversal of the list but is not tail recursive, so creates stack frames.第二种解决方案对列表进行一次遍历,但不是尾递归的,因此创建堆栈帧。

The first solution looks incorrect and gives the elements backwards.第一个解决方案看起来不正确,并且向后提供了元素。 So it should do one traversal of the whole list and then a traversal of n, then possibly another reverse - so it is less efficient in terms of time.所以它应该对整个列表进行一次遍历,然后对 n 进行一次遍历,然后可能再进行一次反向遍历——因此它在时间上的效率较低。

PureScript often makes you decide between these efficiencies, due to strict evaluation.由于严格的评估,PureScript 通常会让您在这些效率之间做出选择。 Could you blow the stack with the size of your list?你能用你的列表的大小来破坏堆栈吗? If so, you have to stick with the theoretically slower, first solution.如果是这样,您必须坚持理论上较慢的第一个解决方案。

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

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