这可能是一个简单的问题,但我已经查阅文档并在谷歌上搜索了示例,仍然不确定答案。
如果我有像这样的列表:
[1,2,3,4,5,6,7,8,9,0]
我想要提取一个切片,比如从索引4到索引8,也就是说我想要:
[5,6,7,8,9]
在 Haskell 中,哪种方式是惯用的?
这可能是一个简单的问题,但我已经查阅文档并在谷歌上搜索了示例,仍然不确定答案。
如果我有像这样的列表:
[1,2,3,4,5,6,7,8,9,0]
我想要提取一个切片,比如从索引4到索引8,也就是说我想要:
[5,6,7,8,9]
在 Haskell 中,哪种方式是惯用的?
首先,那不是一个数组,而是一个列表。我并不是(仅仅)吹毛求疵,因为在Haskell中,数组比列表更加棘手。
话虽如此,一种常见的方法是同时使用take
和drop
:
Prelude> drop 4 . take 9 $ [1,2,3,4,5,6,7,8,9,0]
[5,6,7,8,9]
Prelude> take (9-4) . drop 4 $ [1,2,3,4,5,6,7,8,9,0]
[5,6,7,8,9]
后者更加高效。slice begin end = take (end - begin) . drop begin
- 我相当确信 GHC 可以优化掉第一种实现的低效性。 - Dan Burtontake
延迟计算中得出(额外的比较和递增)。而第二个版本会一次性将所有的丢弃操作完成,所以 take
操作的是普通列表。如果这是性能关键点,则显然需要进行性能分析。可以这样考虑:为了获取第一个值,第一个版本需要从take
中获取5个元素,而第二个版本仅获取一个元素。两个版本在drop
和计算列表方面都做了相同数量的工作。 - Philip JFghci> import Data.Vector
ghci> let v = fromList [1..10]
ghci> v
fromList [1,2,3,4,5,6,7,8,9,10]
ghci> slice 4 5 v
fromList [5,6,7,8,9]
Data.Vector
中,slice
函数的输入参数是切片的起始索引和长度。> drop 4 (take 9 [1,2,3,4,5,6,7,8,9,0])
[5,6,7,8,9]
嗯,不是很实用,但或许可以改进?
(\(x,y) -> if 4 <= y && y <= 9 then [x] else []) =<< zip [1,2,3,4,5,6,7,8,9] [0..]
map snd . filter (liftA2 (&&) (>= 4) (< 9) . fst) . zip [0..]
怎么样(注意 (< 9)
以匹配问题的行为)? - ehirdindexedFilter f = map snd . filter (f.fst) . zip [0..]
的东西,或者更一般化的形式? - Landei