【问题标题】:Grouping a list into lists of n elements in Haskell在 Haskell 中将列表分组为包含 n 个元素的列表
【发布时间】:2012-10-04 06:59:26
【问题描述】:

库中的列表是否存在将 n 个元素组成的组的操作?例如:n=3

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

如果没有,我该怎么做?

【问题讨论】:

  • 如果存在这样的函数,它的类型将是Int -> [a] -> [[a]],所以你可以Hoogle。不过什么也没看到:haskell.org/hoogle/…
  • @MatrixFrog hoogle 默认只搜索几个包,hayoo 搜索更多(我认为甚至是所有的hackage)。
  • @DanielWagner 嗯.. 这个比那个有更好的答案。
  • @AndrewC:我同意,虽然那时标题非常需要编辑。

标签: list haskell


【解决方案1】:

快速搜索Hoogle 发现没有这个功能。另一方面,回复说split包里有一个,叫chunksOf

不过,你可以自己做

group :: Int -> [a] -> [[a]]
group _ [] = []
group n l
  | n > 0 = (take n l) : (group n (drop n l))
  | otherwise = error "Negative or zero n"

当然,有些括号可以去掉,我留在这里是为了理解代码的作用:

基本情况很简单:只要列表为空,只需返回空列表。

递归案例首先测试n 是否为正。如果n0 或更低,我们将进入无限循环,我们不希望这样。然后我们使用takedrop 将列表分成两部分:take 返回第一个n 元素,而drop 返回其他元素。然后,我们将第一个 n 元素添加到通过将我们的函数应用于原始列表中的其他元素而获得的列表中。

【讨论】:

  • 你的错误信息是错误的。 n 在这种情况下不是负数,它不是正数。
【解决方案2】:

此功能以及其他类似功能可以在流行的split 包中找到。

> import Data.List.Split
> chunksOf 3 [1,2,3,4,5,6,7,8,9]
[[1,2,3],[4,5,6],[7,8,9]]

【讨论】:

  • cabal install split
【解决方案3】:

这通常被称为“块”,是最常提到的列表操作之一,它不在base 中。 split 包提供了这样的操作,复制粘贴黑线鳕文档:

 > chunksOf 3 ['a'..'z']
 ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]

此外,与我的意愿相反,hoogle 只搜索一小组库(那些由 GHC 或 HP 提供的库),但您可以使用 +PKG_NAME 将包显式添加到搜索中 - 使用 Int -> [a] -> [[a]] +split 的 hoogle 可以获得您想要的.有些人出于这个原因使用 Hayoo。

【讨论】:

  • 你是如何“导入”拆分的? cabal install split?然后它应该就可以工作了,运行ghci 或使用ghc 编译并确保你使用了import Data.List.Split。如果这是在一个 cabalized 项目中,请务必将 split 添加到构建部门。
【解决方案4】:

你可以自己写一个,正如 Mihai 指出的那样。但我会使用splitAt 函数,因为它不需要像take-drop 组合那样对输入列表进行两次传递:

chunks :: Int -> [a] -> [[a]]
chunks _ [] = []
chunks n xs =
    let (ys, zs) = splitAt n xs
    in  ys : chunks n zs

这是一种常见模式 - 通过重复迭代从种子值(在本例中为您的输入列表)生成列表。这个模式在unfoldr 函数中被捕获。我们可以将它与splitAt 的略微修改版本一起使用(感谢Will Ness 提供更简洁的版本):

chunks n = takeWhile (not . null) . unfoldr (Just . splitAt n)

也就是说,使用unfoldr我们生成n元素的块,同时我们将输入列表缩短n元素,我们生成这些块直到我们得到空列表——此时初始输入被完全消耗。

当然,正如其他人所指出的,您应该使用 split 模块中已经存在的函数。但习惯于标准 Haskell 库中的列表处理函数总是好的。

【讨论】:

  • chunks n xs = takeWhile (not.null) $ unfoldr (Just . splitAt n) xs。 :)
  • 谢谢!这确实是一个更优雅的实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 2017-05-12
  • 2022-01-18
  • 2011-11-16
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多