将列表分组为Haskell中的n个元素的列表

177*_*775 23 haskell list

库中的列表上是否有一个操作来生成n个元素的组?例如:n = 3

groupInto 3 [1,2,3,4,5,6,7,8,9] = [[1,2,3],[4,5,6],[7,8,9]]
Run Code Online (Sandbox Code Playgroud)

如果没有,我该怎么办?

Mih*_*eac 45

快速搜索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"
Run Code Online (Sandbox Code Playgroud)

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

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

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

在此输入图像描述

  • 好图!+1 (9认同)
  • 您的错误消息是错误的.在这种情况下,`n`不是负数,它不是正数. (4认同)

ham*_*mar 31

此功能以及其他类似功能可以在流行的拆分包中找到.

> import Data.List.Split
> chunksOf 3 [1,2,3,4,5,6,7,8,9]
[[1,2,3],[4,5,6],[7,8,9]]
Run Code Online (Sandbox Code Playgroud)

  • `阴谋集团安装分裂` (3认同)

Mar*_*ila 13

Mihai指出,你可以自己写一个.但是我会使用splitAt函数,因为它不需要输入列表上的两次传递,就像下拉组合那样:

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

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

chunks n = takeWhile (not.null) . unfoldr (Just . splitAt n)
Run Code Online (Sandbox Code Playgroud)

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

当然,正如其他人指出的那样,您应该使用split模块中已有的函数.但是,习惯于使用标准Haskell库中的列表处理函数总是很好的.

  • `chunks n xs = takeWhile(not.null)$ unfoldr(Just.splitAt n)xs`.:) (5认同)

Tho*_*son 6

这被称为"块",并且是最常提到的列表操作之一base.该软件包split提供了这样的操作,复制并粘贴了haddock文档:

 > chunksOf 3 ['a'..'z']
 ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]
Run Code Online (Sandbox Code Playgroud)

此外,根据我的意愿,hoogle只搜索一小组库(GHC或HP提供的库),但您可以使用+PKG_NAME- hoogle 明确地将搜索包添加到搜索中,Int -> [a] -> [[a]] +split获得您想要的内容.有些人因此而使用Hayoo.