Разделить коллекцию на подколлекции в Groovy

У меня есть массив, содержащий неизвестное количество элементов, которые я хотел бы разбить на отдельные массивы, чтобы каждый отдельный массив содержал не более 4 элементов. Как лучше всего это сделать в Groovy? Спасибо!


person RyanLynch    schedule 30.06.2010    source источник
comment
Начиная с groovy 1.8.6 вы можете использовать метод сортировки в списках.   -  person tim_yates    schedule 10.02.2012


Ответы (3)


У нас было это здесь: Как разделить список в списки одинакового размера в Groovy?

Я придумал это:

List.metaClass.partition = { size ->
  def rslt = delegate.inject( [ [] ] ) { ret, elem ->
    ( ret.last() << elem ).size() >= size ? ret << [] : ret
  }
  !rslt.last() ? rslt[ 0..-2 ] : rslt
}

def list = [1, 2, 3, 4, 5, 6].partition( 4 )

Что должно дать вам:

[ [ 1, 2, 3, 4 ], [ 5, 6 ] ]

Обновлять!

В Groovy 1.8.6+ вы можете использовать list.collate( 4 ) для получения того же результата.

person tim_yates    schedule 30.06.2010
comment
@RaffiM с Groovy 1.8.6+ вы можете использовать list.collate( 4 ), чтобы получить тот же результат :-) - person tim_yates; 29.02.2012
comment
Где лучше всего определить метод partition в большом приложении? Делать его частью List.metaClass нецелесообразно, поскольку он существует только в контексте класса groovy, в котором он определен. - person raffian; 29.02.2012
comment
@RaffiM Я бы обновил groovy и использовал collate ;-), если это не удастся, если вы добавите его в цикл запуска своего приложения. Или переписать его как категорию? - person tim_yates; 29.02.2012
comment
Мы пока не используем эту версию Groovy... может ли метод разделения быть автономным, как служебная функция? Какие детали пришлось бы менять? - person raffian; 01.03.2012
comment
@RaffiM есть еще одна функциональная версия здесь - person tim_yates; 01.03.2012

Ответ tim_yates — это круто, но он выбрасывает java.lang.ArrayIndexOutOfBoundsException в пустые списки (например: [].partition(4)). Это можно исправить таким образом:

List.metaClass.partition = {size ->
    if (!delegate)
        return []

    def rslt = delegate.inject([[]]) {ret, elem ->
        (ret.last() << elem).size() >= size ? (ret << []) : ret
    }
    !rslt.last() ? rslt[0..-2] : rslt
}

assert [].partition(4) == []
assert [1, 2, 3, 4, 5, 6].partition(4) == [[1, 2, 3, 4], [5, 6]]
person Rorick    schedule 30.06.2010
comment
хороший улов! Можно также превратить последнюю строку в !rslt[ 0 ] ? [] : !rslt.last() ? rslt[ 0..-2 ] : rslt - person tim_yates; 01.07.2010
comment
@Rorick Я проверил вышеприведенное со списком, и он работает без каких-либо изменений в этой функции. Обрабатывает ли Groovy списки и массивы одинаково? - person raffian; 01.03.2012
comment
В основном, но могут быть отличия. Например, у списка нет свойства length, а у массивов есть. Но в большинстве случаев массивы ведут себя так же, как списки. - person Rorick; 05.03.2012

Начиная с Groovy 1.8.6, вы можете использовать подборку:

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

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

Кредит на серию Groovy Goodness от Mrhaki: http://mrhaki.blogspot.com.au/2012/04/groovy-goodness-collate-list-into-sub.html

person Armin    schedule 03.06.2014