【问题标题】:List comprehension: making lists of lists列表理解:制作列表列表
【发布时间】:2010-11-16 17:31:44
【问题描述】:

嗨,我试图在 haskell 中创建一个函数,该函数接受一个数字 a 使用列表将其分割,即对于数字 4,它将创建 [[1,1,1,1],[1,1,2],[1,3],[2,2],[4]]。我正在考虑对此使用列表推导,它将创建列表 x,然后使用 [1...n] 中的数字(n 是我想要的分区号)创建更多列表,其中创建的列表的总和将相等到 n.

到目前为止我创建的代码是-

partions (n:xs) = [[x|x<-[1...n], sum[x]==n]]|xs<-[1..]]

但显然它不起作用,有什么建议吗?

谢谢。

【问题讨论】:

  • 回滚删除帖子的编辑
  • 再一次。 @dave,您为什么要尝试删除这两个问题? ://

标签: haskell list-comprehension


【解决方案1】:

我建议尝试递归:要获得 n 的分区,迭代数字 i = 1 到 n,并递归生成 (n-i) 的分区,基本情况是 1 的唯一分区是 1 本身,并且0 的分区是空列表。

【讨论】:

  • 使partition 0 成为[[]] 而不是[] 可能有助于简化递归。
  • @Joey 这是真的。我对自己要做什么的描述有点草率。
【解决方案2】:

这个怎么样...

import Data.List (nub, sort)

parts :: Int -> [[Int]]
parts 0 = []
parts n = nub $ map sort $ [n] : [x:xs | x <- [1..n`div`2], xs <- parts(n - x)]

尝试一下:

*Main Control.Monad> forM [1..5] (print . parts)
[[1]]
[[2],[1,1]]
[[3],[1,2],[1,1,1]]
[[4],[1,3],[1,1,2],[1,1,1,1],[2,2]]
[[5],[1,4],[1,1,3],[1,1,1,2],[1,1,1,1,1],[1,2,2],[2,3]]

我认为这是正确的,如果没有效率的话。

【讨论】:

    【解决方案3】:

    我发现定义一个辅助函数partitionsCap 很有帮助,它不允许任何项目大于给定值。递归使用,它可以用来只产生你想要的monotonically递减结果(即当你已经有[1,1,3]时没有[1,3,1]):

    partitions :: Int -> [[Int]]
    partitions n = partitionsCap n n
    
    partitionsCap :: Int -> Int -> [[Int]]
    partitionsCap cap n
        | n < 0  = error "partitions: negative number"
        | n == 0 = [[]]
        | n > 0  = [i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
                   where hi = min cap n
    

    算法的核心思想是,在对 N 进行分区时,将 in 减少到 1,并将 i 预先添加到 n-i 的分区中。简化:

    concat [map (i:) $ partitions (n-i) | i <- [n,n-1..1]]
    

    但是错了:

    > partitions 3
    [[3],[2,1],[1,2],[1,1,1]]
    

    我们希望 [1,2] 消失。因此,我们需要限制我们预先设置的分区,这样它们就不会超过i

    concat [map (i:) $ partitionsCap i (n-i) | i <- [hi,hi-1..1]]
    where hi = min cap n
    

    现在,清理一下:concatmap 如此靠近引起了我的注意。一点背景知识:列表推导和列表单子是 very closely relatedconcatMap&gt;&gt;= 相同,但在列表单子中其参数被翻转。所以我想知道:那些 concatmap 能否以某种方式变成&gt;&gt;=,而&gt;&gt;= 能否以某种方式甜言蜜语进入列表理解? p>

    在这种情况下,答案是肯定的:-)

    [i : p | i <- [hi,hi-1..1], p <- partitionsCap i (n-i)]
    where hi = min cap n
    

    【讨论】:

      【解决方案4】:

      我对 Haskell 有点生疏了,但也许下面的代码可以指导你找到解决方案。

      parts :: Int -> Int -> [[Int]]
      parts 0 p = [[]]
      parts x p = [(y:ys) | y <-[p..x], ys <- (parts (x - y) y)]
      

      然后你必须用 x = n 和 p = 1 来调用部件。

      编辑

      我已经修复了当 x 等于 0 以返回包含单个项目的列表时的基本情况,因为该项目是一个空列表。现在它工作正常:)

      【讨论】:

      • 也许我遗漏了一些东西,但我收到一个错误:无法将预期类型 t1->t 与推断类型 [[Int]] 匹配。在表达式中:parts 4 1. 在“it”的定义中:it = parts 4 1
      • @Matt 我不是专家,但我认为您可能在另一种情况下使用it,并且it 的类型推断与[[Int]] 不匹配。我使用 WinHugs 调用了parts 4 1,输出与@dave 的示例完全相同
      • 你不应该定义“它”。 'it' 始终是 GHCi 中最后一次计算的结果。
      猜你喜欢
      • 2014-02-25
      • 1970-01-01
      • 1970-01-01
      • 2022-11-29
      • 1970-01-01
      • 1970-01-01
      • 2019-08-13
      • 2013-06-24
      • 1970-01-01
      相关资源
      最近更新 更多