【问题标题】:Haskell all possible ways to remove 1 element from the listHaskell从列表中删除1个元素的所有可能方法
【发布时间】:2017-01-10 19:06:15
【问题描述】:

这是我到目前为止写的,但我有点迷失了:

removeone :: [a] -> [[a]]
removeone [] = []
removeone (a:as) = [as] -- I'm lost here

这是我正在寻找的输出类型:

removeone [1,2,3] = [[2,3],[1,3],[1,2]]
removeone [1,2]   = [[1],[2]]

解决此问题的最佳方法是什么?在 Java 中,我只是循环它,每次生成一个新列表,我会附加到一个预先存在的列表中。把它翻译成 Haskell 时我很迷茫。

【问题讨论】:

  • removeone (a:as) = as : map (a:) (removeone as)
  • @user2407038 请不要将答案发布为 cmets。
  • @user2407038 我正要发布它作为答案,但现在我感觉很糟糕......

标签: list haskell recursion


【解决方案1】:

让我们看一个稍微长一点的例子,看看如何分解它:

> removeone [1,2,3,4]
[[2,3,4],[1,3,4],[1,2,4],[1,2,3]]

正如您已经猜到的那样,您只需将as(从输入中删除第一个元素的结果)放在一些列表的前面,但那是什么列表?

removeone (a:as) = as : ...

仔细观察,您可以看到a == 1 位于它们每个人的前面。让我们考虑一下如何构建它:

[[1,3,4],[1,2,4],[1,2,3]] == [1:[3,4],1:[2,4],1:[2,3]]
                          == map (1:) [[3,4],[2,4],[2,3]]

第二个参数应该看起来很熟悉:这是您应该期望removeone [2,3,4] 的结果的样子。就像这样,你有你的递归案例:

removeone (a:as) = as : map (a:) (removeone as)

【讨论】:

    【解决方案2】:

    惯用的递归解决方案由@сhepner 给出。然而,日常的 Haskell 不是关于递归,它更多的是关于递归模式和问题的精确表述。如果我得到了它,我最终会得到以下解决方案

    import Data.List (inits, tails)
    
    removeone :: [a] -> [[a]]
    removeone lst = zipWith (++) (inits lst) (tail (tails lst))
    

    它比显式递归快 2 倍以上,而且看起来更像是对问题的表述。在这里使用“危险”函数tail 是安全的,因为tails [] = [[]]。琐碎案件由zipWithinitstails持有。

    如果生成的补充列表应该经过非平凡的处理(例如,它们代表了一个组中每个游戏人物的视图),请考虑使用 Zippers 并利用它们的共同属性(它真的不像听起来那么吓人:))。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多