Разделить список на подсписки, похожие на сортировку, но с максимальным размером результата - PullRequest
1 голос
/ 10 января 2020

Допустим, у меня есть список

def letters = 'a' .. 'g'

Я знаю, что могу использовать сортировку для создания списка подсписков одинакового размера (плюс остаток).

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

Но я хочу получить список с указанным c размером подсписков, где элементы исходного списка разделены на подсписки, которые настолько велики, насколько это необходимо для получения наиболее равномерного распределения подсписка. размер. Пример:

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]]

Кто-нибудь знает, есть ли такие волхвы c существует или мне придется самому кодировать это?

1 Ответ

3 голосов
/ 11 января 2020

Нет ничего встроенного в 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]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...