公平地对列表进行分区

时间:2017-02-11 00:04:49

标签: list haskell partitioning

我确信这是一个相当普遍的事情,但我找不到任何东西(我的网络搜索功能不强)。

我有一个函数可以将列表分组为每个N个元素的列表列表,如果列表的长度不能被N整除,则最终子列表小于N.一些例子:

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

我想要的是获取一个列表和一个正整数 n (在上面的例子中 n 可以说是2和3)并将其划分为 n 列表的新列表。它应该在任何类型的列表上工作,并生成尺寸尽可能小的子列表。

所以我想:

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

或任何子列表组合,只要有长度为3和长度为4的两个。

使用groupEvery的天真尝试:

fairPartition :: Int -> [a] -> [[a]]
fairPartition n xs = groupEvery ((length xs `div` n) + 1) xs

fairPartition 4 [1..10] = [[1,2,3],[4,5,6],[7,8,9],[10]]

但是你可以看到(3,3,3,1)不是公平的长度分布,对于较小长度的列表,它甚至没有返回正确数量的子列表:

# Haskell, at GHCi
*Main> let size = 4 in map (\l -> length . fairPartition 4 $ [1..l]) [size..25]
[2,3,3,4,3,3,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4]

我想要一个{pseudo,actual} -code函数或解释,可以很容易地翻译成Haskell(身份翻译将是最好的!)。

感谢。

1 个答案:

答案 0 :(得分:3)

您可以使用split包的splitPlaces功能。

import Data.List.Split

fairPartition n xs = case length xs `quotRem` n of
    (q, r) -> splitPlaces (replicate r (q+1) ++ replicate (n-r) q) xs