【问题标题】:Get a sublist in Haskell在 Haskell 中获取子列表
【发布时间】:2012-01-21 17:20:59
【问题描述】:

可能是一个简单的问题,但我浏览了文档并搜索了示例,但我仍然不确定答案。

如果我有这样的列表:

[1,2,3,4,5,6,7,8,9,0]

我想提取一个切片,比如从索引 4 到索引 8,即我想要:

[5,6,7,8,9]

在 Haskell 中执行此操作的惯用方式是什么?

【问题讨论】:

标签: haskell


【解决方案1】:
> drop 4 (take 9 [1,2,3,4,5,6,7,8,9,0])

[5,6,7,8,9]

【讨论】:

    【解决方案2】:

    嗯,不是很实用,但也许可以改进一下?

    (\(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 (&amp;&amp;) (&gt;= 4) (&lt; 9) . fst) . zip [0..] 怎么样(注意 (&lt; 9) 以匹配问题的行为)?
    • decorate-process-undecorate 方法对于这个问题似乎需要做很多额外的工作。
    • 也许应该有 indexedFilter f = map snd . filter (f.fst) . zip [0..] 之类的东西或库中的概括?
    • @Landei:对我来说似乎用途太有限了。通常有一些方法可以解决问题,而无需借助压缩索引。
    【解决方案3】:

    你可能对Data.Vector (slice)感兴趣。

    ghci> 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开始索引切片长度作为输入。

    【讨论】:

      【解决方案4】:

      首先,这不是一个数组,而是一个列表。我不是(仅仅)迂腐,因为在 Haskell 中数组比列表更成问题。

      也就是说,一种常见的方法是将takedrop 一起使用:

      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]
      

      后者效率更高。

      【讨论】:

      • 太棒了,谢谢 - 我也更正它说列表而不是数组:)
      • @ehird:您刚刚列出了我称它们有问题的主要原因。我没有称它们为“无用”和“有害”:-)
      • 泛化:slice begin end = take (end - begin) . drop begin - 我也很确定 GHC 可以优化第一次实施的低效率。
      • 是的,我很确定效率评论不准确;即使进行简单的非严格评估,您也永远不会在列表中“看得太远”,所以除非 GHC 悲观,我对此表示怀疑,第一个更清晰的版本应该一切正常。
      • @ehird,天真地它会降低效率,因为删除的每个值都将根据 take thunk 计算(额外的比较和增量)。虽然第二个版本一次性完成所有删除,但take 使用普通列表进行操作。显然,如果这对性能至关重要,则分析是必不可少的。可以这样想:要获取第一个值,第一个版本需要从take 获取5,而第二个版本只从take 获取一个元素。两个版本在 drop 和计算列表中的工作量相同。
      猜你喜欢
      • 2021-03-07
      • 2017-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多