Reputation: 1710
Let's say I have a list
def letters = 'a' .. 'g'
I know that I can use collate to create a list of sub-lists of equal size (plus the remainder).
assert letters.collate(3) == [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]
But what I want is to get a list of a specific size of sub-lists, where the items of the original list are split into sublists that are as big as needed to get the most equal distribution of the sub-list size. Example:
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]]
Lists that are smaller than the max_size would produce a list of the same size as the original of single element lists:
def numbers = 1..7
assert numbers.collateIntoFixedSizeList(10) == [[1],[2],[3],[4],[5],[6],[7]]
Does anybody know whether such magic exists or will I have to code this up myself?
Upvotes: 1
Views: 878
Reputation: 171084
There's nothing built in to Groovy to do this, but you could write your own:
def fancyCollate(Collection collection, int groupCount) {
collection.indexed().groupBy { i, v -> i % groupCount }.values()*.values()
}
Or, you could do this, which creates less intermediate objects:
def fancyCollate(Collection collection, int groupCount) {
(0..<collection.size()).inject([[]] * groupCount) { l, v ->
l[v % groupCount] += collection[v]
l
}
}
Try #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']
Try #3 (with your example)
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]]
Upvotes: 3