2017-02-11 92 views
2

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

我有一个功能,可以组的列表到每个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]] 

我要的是要接受列表和一个正整数ñ(在上面的例子中ň可以说是2和3),并将其分割成的ñ列出一个新的列表。它应该在任何类型的列表上工作,并生成尺寸相差尽可能小的子列表。

所以我想有:

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

或者只要有使用groupEvery 2长度3和长度4

一个天真的尝试的一个子列表的任意组合:

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] 

我想{伪,实际}代码功能或解释,很容易翻译成哈斯克尔(身份翻译将是最好的!)。

感谢。

+2

怎么样'转置。每个人都有团体吗?订单是否重要或列表元素是否可以被视为集合? – chi

+0

不,订单对我来说并不重要,所以我认为它确实是这样。谢谢!尽管我希望看到一个为了好奇和普遍性而订购的重要解决方案。 – Jxek

回答

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 
+0

不错。我正在寻找这个(splitPlaces)。不能相信我错过了它。 – Alec