3

I have an array containing an unknown number of items that I would like to split into separate arrays so that each separate array contains no more than 4 items. What is the best way to do this in Groovy? Thanks!

RyanLynch
  • 2,987
  • 3
  • 35
  • 48
  • 1
    As of groovy 1.8.6 you can use the [collate method](http://jira.codehaus.org/browse/GROOVY-5283) on Lists – tim_yates Feb 09 '12 at 21:48

3 Answers3

9

We had this here: How to split a list into equal sized lists in Groovy?

I came up with this:

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 )

Which should give you:

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

Update!

With Groovy 1.8.6+ you can use list.collate( 4 ) to get the same result

Community
  • 1
  • 1
tim_yates
  • 167,322
  • 27
  • 342
  • 338
  • 2
    @RaffiM With Groovy 1.8.6+ [you can use `list.collate( 4 )`](http://blog.bloidonia.com/post/18073244930/whats-new-in-groovy-1-8-6-the-collate-method) to get the same result :-) – tim_yates Feb 29 '12 at 08:40
  • In a large application, where is the best place to define the `partition` method? Making it part of the `List.metaClass` is not practical since it only exists in the context of the groovy class where it's defined. – raffian Feb 29 '12 at 19:32
  • @RaffiM I would upgrade groovy and use `collate` ;-) failing that, if you add it at the startup cycle of your app. Or rewrite it as a category? – tim_yates Feb 29 '12 at 19:42
  • We're not using that Groovy version just yet...can the partition method be standalone, like a utility function? What parts would have to change? – raffian Feb 29 '12 at 20:06
  • 1
    @RaffiM there's another functional version [over here](http://stackoverflow.com/a/2926548/6509) – tim_yates Feb 29 '12 at 20:40
6

Answer by tim_yates is cool, but it throws java.lang.ArrayIndexOutOfBoundsException on empty lists (for example: [].partition(4)). This can be fixed in this way:

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]]
Rorick
  • 8,857
  • 3
  • 32
  • 37
  • good catch! Could also turn last line into `!rslt[ 0 ] ? [] : !rslt.last() ? rslt[ 0..-2 ] : rslt` – tim_yates Jun 30 '10 at 21:15
  • @Rorick I tested the above with a list, and it works without changing a single thing in that function, does Groovy treat Lists and Arrays equally? – raffian Mar 01 '12 at 17:50
  • Mostly but there can be differences. For instance, list has no `length` property while arrays have. But in most cases arrays behave in the same way as lists. – Rorick Mar 05 '12 at 15:30
4

Since Groovy 1.8.6, you can use collate:

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

Credit to Mrhaki's Groovy goodness series: http://mrhaki.blogspot.com.au/2012/04/groovy-goodness-collate-list-into-sub.html

Armin
  • 1,367
  • 1
  • 12
  • 17