2017-02-11 89 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