Haskell “按大小分组列表”是折叠的吗?

Haskell “按大小分组列表”是折叠的吗?,haskell,Haskell,我遇到了这个问题:按相同大小的数据包对列表中的元素进行分组,以便 > groupBy 3 [1..10] [[1,2,3], [4,5,6], [7,8,9], [10]] 没有什么真正困难的事情要做,但首先我很惊讶,我找不到它的函数。 我的第一次尝试是 groupBy _ [] = [] groupBy n xs = g : groupBy n gs where (g, gs) = splitAt n xs 到目前为止还不错,即使是在无限列表中,它也

我遇到了这个问题:按相同大小的数据包对列表中的元素进行分组,以便

> groupBy 3 [1..10] 
[[1,2,3], [4,5,6], [7,8,9], [10]]
没有什么真正困难的事情要做,但首先我很惊讶,我找不到它的函数。 我的第一次尝试是

 groupBy _ [] = []
 groupBy n xs = g : groupBy n gs
              where (g, gs) = splitAt n xs
到目前为止还不错,即使是在无限列表中,它也能工作。但是我不喜欢第一行
groupBy[]=[]
。似乎是一个很好的折叠候选人,但我想不出来

那么这个函数可以写成折页还是一行呢

更新 我在一条航线上的尝试:

groupBy' n l = map (map snd) $ groupBy ((==) `on` fst) $ concatMap (replicate n) [1..] `zip` l
我花了10倍多的时间才写出了最初的尝试

更新2 按照Ganesh的回答,使用
unfover
pointfree
的帮助,我得出了这个复杂的无点解决方案

groupBy' n = unfoldr $ listToMaybe . (ap (>>) (return.splitAt n))
你可以通过一些体操来做折叠动作,但作为一个:

[您需要
导入数据。如果尚未导入,请列出
]

展开器的类型为:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
展开器
的思想是,生成函数决定是停止(
)还是继续(
只是
)。如果结果是
Just
,则元组的第一个元素是输出列表的下一个元素,第二个元素再次传递给生成函数


正如@leftroundaound在对该问题的评论中指出的那样,展开在这里更为自然,因为它将输出列表元素视为彼此相似,而在折叠中,输入列表元素应被视为相似。在这种情况下,需要在输入列表的每个
n
元素中启动一个新的子列表,这使得这一点更加困难。

您的原始解决方案肯定是首选方案。如果你有一个
[]
模式和一个
(x:xs)
,那么,是的,你应该把它做成一个
foldr
,但是在这里你需要对它进行一些按摩以适应它。这种混淆超过了任何好处。按照Ganesh的建议展开效果更好,因为在结果列表中,元素“处于同等地位”,而在输入中,位置mod
n
会更改元素的操作。这就是我要寻找的展开。如果您对库函数感兴趣,
Data.List.Split中有
chunksOf
@bmaderbacher:这就是我最初想要的。然而,我在胡格尔上找不到它。它只能在大量没有正确签名的函数之后找到
文本版本和它。@mb14
Data.List.Split
是Haskell平台的一部分。为了搜索函数,我更喜欢FPComplete的Hoogle,它有更多的函数索引。我意识到
fold
很笨拙,但需要
fold
家族中的一些东西,这确实是
unfover
。是否可以使用listToMaybe或其他东西删除
if-then-else
?我看不到任何明显的东西-
listToMaybe
只返回列表的第一个元素。你的选择确实很复杂:-)如果你真的喜欢,你可以用-XLambdaCase:
\n->unfover(\case{[]->Nothing;xs->Just$splitAt n xs})保存几个字符。
我不是想保存字符,我只是想知道如何删除
If[]then Nothing
,它看起来像一个经典的模式。我当前的代码使用了我文章中的第一个版本,我将坚持使用它。@mb14 listToMaybe的技巧很好,尽管编码混乱(
ap
>
从两个不同的单子返回
)<代码>展开器(\xs->listToMaybe[splitAt n xs|_
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]