繁体   English   中英

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

[英]Grouping a list into lists of n elements in Haskell

是否对库中的列表进行了操作,可以生成 n 个元素的组? 例如:n=3

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

如果没有,我该怎么做?

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元素添加到通过将我们的函数应用于原始列表中的其他元素而获得的列表中。

在此处输入图片说明

此功能以及其他类似功能可以在流行的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]]

正如 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版本splitAt (感谢Will Ness提供更简洁的版本):

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM