haskell - 占用列表的最后 n 个元素的最有效方法是什么

标签 haskell

澄清:我想要所有元素,但最后一个 n
阅读有关 stackoverflow 的一些答案,我觉得在列表中使用长度是不可取的。那么有没有比 take (length xs - n) xs 更好的方法呢? ?

最佳答案

.你先放下n列表中的元素,然后同时遍历两个列表,当您使用列表的删除版本到达列表末尾时,您将返回整个列表中的“迭代器”列表:

takeLast :: Int -> [a] -> [a]
takeLast n ls = go (drop n ls) ls
    where go [] ls = ls
          go (_:xs) ~(_:ys) = go xs ys
因此这是有效的,因为第一个“迭代器”提前了 n 步。因此,如果它到达列表末尾,则第二个迭代器在列表末尾后面 n 步。
例如:
Prelude> takeLast 2 [1,4,2,5,1,3,0,2]
[0,2]
Prelude> takeLast 3 [1,4,2,5,1,3,0,2]
[3,0,2]
Prelude> takeLast 4 [1,4,2,5,1,3,0,2]
[1,3,0,2]
Prelude> takeLast 5 [1,4,2,5,1,3,0,2]
[5,1,3,0,2]
我们也可以删除最后一个 n元素以类似的方式:
dropLast :: Int -> [a] -> [a]
dropLast n ls = go (drop n ls) ls
    where go [] _ = []
          go (_:xs) ~(y:ys) = y : go xs ys
例如:
Prelude> dropLast 2 [1,4,2,5,1,3,0,2]
[1,4,2,5,1,3]
Prelude> dropLast 3 [1,4,2,5,1,3,0,2]
[1,4,2,5,1]
Prelude> dropLast 4 [1,4,2,5,1,3,0,2]
[1,4,2,5]
Prelude> dropLast 5 [1,4,2,5,1,3,0,2]
[1,4,2]
如果我们对一个无限列表进行操作,那么 dropLast仍然会产生元素,而如果我们使用 take (length ls - n) ls ,它会陷入无限循环。
我们可以,如 @DanielWagner says使用 zipWith为了这:
dropLast :: Int -> [a] -> [a]
dropLast n xs = zipWith const xs (drop n xs)
这里我们让zipWith遍历两个列表,我们使用 const每次返回第一个列表的元素。

关于haskell - 占用列表的最后 n 个元素的最有效方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64390393/

相关文章:

c++ - 将 C++ 代码翻译成 Haskell

haskell - QuickCheck 2 有什么新功能?

haskell - threepenny-gui:如何获取文字?

haskell - 在 Haskell 中是否有一种自动内存全局多态值的方法?

Haskell RSA 示例

haskell - 了解 Monad '>>=' 函数中的 forall 吗?

haskell - MaybeT 的 runMaybeT 参数

parsing - Parsec:获取表达式的开始和结束源位置?

haskell - 如何 'show' 无法显示的类型?

haskell - (重新)-定义(==)类 Eq