将列表拆分为子列表,类似于排序,但结果最大大小



假设我有一个列表

def letters = 'a' .. 'g'

我知道我可以使用 collate 来创建大小相等的子列表列表(加上其余部分(。

assert letters.collate(3) == [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

但我想要的是获得一个特定大小的子列表的列表,其中原始列表的项目被拆分为子列表,这些子列表的大小与子列表大小的最平均分布一样大。例:

def numbers = 1..7
assert numbers.collateIntoFixedSizedList(5) == [[1,2], [3,4], [5], [6], [7]]
// the elements that contain two items could be at the end of the list as well
// doesn't matter much to me
assert numbers.collateIntoFixedSizedList(5) == [[1], [2], [3], [4,5], [6,7]]

小于max_size的列表将生成与单个元素列表的原始列表大小相同的列表:

def numbers = 1..7
assert numbers.collateIntoFixedSizeList(10) == [[1],[2],[3],[4],[5],[6],[7]]

有谁知道这种魔力是否存在,或者我必须自己编写代码吗?

Groovy没有内置任何东西来做到这一点,但你可以自己编写:

def fancyCollate(Collection collection, int groupCount) {
collection.indexed().groupBy { i, v -> i % groupCount }.values()*.values()
}

或者,您可以这样做,这将创建较少的中间对象:

def fancyCollate(Collection collection, int groupCount) {
(0..<collection.size()).inject([[]] * groupCount) { l, v ->
l[v % groupCount] += collection[v]
l
}
}

尝试 #2 ;-(

def fancyCollate(Collection collection, int size) {
int stride = Math.ceil((double)collection.size() / size)
(1..size).collect { [(it - 1) * stride, Math.min(it * stride, collection.size())] }
.collect { a, b -> collection.subList(a, b) }
}
assert fancyCollate('a'..'z', 3) == ['a'..'i', 'j'..'r', 's'..'z']

尝试#3(以您的示例(

Collection.metaClass.collateIntoFixedSizeList = { int size ->
int stride = Math.ceil((double)delegate.size() / size)
(1..Math.min(size, delegate.size())).collect { [(it - 1) * stride, Math.min(it * stride, delegate.size())] }
.collect { a, b -> delegate.subList(a, b) }
}
def numbers = (1..7)
assert numbers.collateIntoFixedSizeList(10) == [[1],[2],[3],[4],[5],[6],[7]]

最新更新