32

If I have this:

def array = [1,2,3,4,5,6]

Is there some built-in which allows me to do this ( or something similar ):

array.split(2)

and get:

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

?

raffian
  • 31,267
  • 26
  • 103
  • 174
Geo
  • 93,257
  • 117
  • 344
  • 520
  • 5
    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:51

9 Answers9

86

EDIT As of groovy 1.8.6 you can use the collate method on lists

def origList = [1, 2, 3, 4, 5, 6, 7, 8, 9]
assert [[1, 2, 3, 4], [5, 6, 7, 8], [9]] == origList.collate(4)

Another method using inject and metaClasses

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

def origList = [1, 2, 3, 4, 5, 6]

assert [ [1], [2], [3], [4], [5], [6] ] == origList.partition(1)
assert [ [1, 2], [3, 4], [5, 6] ]       == origList.partition(2)
assert [ [1, 2, 3], [4, 5, 6] ]         == origList.partition(3)
assert [ [1, 2, 3, 4], [5, 6] ]         == origList.partition(4)
assert [ [1, 2, 3, 4, 5], [6] ]         == origList.partition(5)
assert [ [1, 2, 3, 4, 5, 6] ]           == origList.partition(6)
assert [ ]                              == [ ].partition(2)

Edit: fixed an issue with the empty list

mkobit
  • 43,979
  • 12
  • 156
  • 150
tim_yates
  • 167,322
  • 27
  • 342
  • 338
22

I agree with Chris that there isn't anything built into groovy to handle this (at least for more than 2 partitions), but I interpreted your question to be asking something different than he did. Here's an implementation that does what I think you're asking for:

def partition(array, size) {
    def partitions = []
    int partitionCount = array.size() / size

    partitionCount.times { partitionNumber ->
        def start = partitionNumber * size 
        def end = start + size - 1
        partitions << array[start..end]    
    }

    if (array.size() % size) partitions << array[partitionCount * size..-1]
    return partitions    
}


def origList = [1, 2, 3, 4, 5, 6]
assert [[1], [2], [3], [4], [5], [6]] == partition(origList, 1)
assert [[1, 2], [3, 4], [5, 6]] == partition(origList, 2)
assert [[1, 2, 3], [4, 5, 6]] == partition(origList, 3)
assert [[1, 2, 3, 4], [5, 6]] == partition(origList, 4)
assert [[1, 2, 3, 4, 5], [6]] == partition(origList, 5)
assert [[1, 2, 3, 4, 5, 6]] == partition(origList, 6)
Ted Naleid
  • 26,511
  • 10
  • 70
  • 81
  • Yeah. This is what I was looking for. I ended up writing my own last night. Thanks! – Geo May 28 '10 at 08:23
  • @Ted Possible concurrency issue with this function in some scenarios, but easily addressable, http://stackoverflow.com/questions/9536552/groovy-collating-list-causes-concurrentmodification-exception – raffian Mar 02 '12 at 21:09
17

Check out groovy 1.8.6. There is a new collate method on List.

def list = [1, 2, 3, 4]
assert list.collate(4) == [[1, 2, 3, 4]] // gets you everything   
assert list.collate(2) == [[1, 2], [3, 4]] //splits evenly
assert list.collate(3) == [[1, 2, 3], [4]] // won't split evenly, remainder in last list.

Take a look at the Groovy List documentation for more info because there are a couple of other params that give you some other options, including dropping the remainder.

benkiefer
  • 739
  • 6
  • 10
9

I was looking for the same problem and I found the collate() method for lists to be very useful.

array.collate(2)

Here is the link to the documentation.

fhdrsdg
  • 10,297
  • 2
  • 41
  • 62
Paresh
  • 156
  • 1
  • 3
4

There is nothing builtin to do that but it is not hard to write:

def array = [1,2,3,4,5,6]
int mid = (int) (array.size() / 2)
def left = array[0..mid-1]
def right = array[mid..array.size()-1]

println left
println right
Chris Dail
  • 25,715
  • 9
  • 65
  • 74
3

Here's an alternative version, that uses Groovy's dynamic features to add a split method to the List class, that does what you expect:

List.metaClass.split << { size ->
  def result = []
  def max = delegate.size() - 1
  def regions = (0..max).step(size)

  regions.each { start ->
     end =  Math.min(start + size - 1, max)
     result << delegate[start..end]
  }

  return result
}

def original = [1, 2, 3, 4, 5, 6]
assert [[1, 2], [3, 4], [5, 6]] == original.split(2)
Christoph Metzendorf
  • 7,968
  • 2
  • 31
  • 28
2

I know this is super old - but for those looking to split a list into equal partitions (with remainders), and you miss Tim's comment on the original post, the most recent groovy way is the collate() method for List objects that has been available since Groovy 1.8.6.

def array = [1, 2, 3, 4, 5, 6, 7]

assert [[1], [2], [3], [4], [5], [6], [7]] == array.collate(1, 1, true)
assert [[1, 2], [3, 4], [5, 6], [7]] == array.collate(2, 2, true)
assert [[1, 2, 3], [4, 5, 6], [7]] == array.collate(3, 3, true)
assert [[1, 2, 3, 4], [5, 6, 7]] == array.collate(4, 4, true)
assert [[1, 2, 3, 4, 5], [6, 7]] == array.collate(5, 5, true)
assert [[1, 2, 3, 4, 5, 6], [7]] == array.collate(6, 6, true)
assert [[1, 2, 3, 4, 5, 6, 7]] == array.collate(7, 7, true)
Mark
  • 21
  • 1
1
List.metaClass.split << { step ->
    def result = [], max = delegate.size(), min = 0 

    while(min+step < max){       
        result.add delegate.subList(min,min+=step)
    }
    result.add delegate.subList(min, max)

    result
}
devside
  • 2,171
  • 1
  • 19
  • 23
0

This question is old, but I want to share anyway what I came up with to split a list in equal sized lists.

list.collate is great, but did not work for me, as I needed the lists to be split evenly.

Where is what I do:

class PartitionCategory {

    static evenlyPartitionWithCount(Collection self, int count) {
        def indexes = 0..<self.size()
        def sizes = indexes.countBy({ i -> i % count }).values()
        def ranges = sizes.inject([]) { a, v -> a << (a ? (a.last().last() + 1)..(a.last().last() + v) : 0..<v) }
        ranges.collect { r -> self[r] }
    }

    static evenlyPartitionWithSize(Collection self, int size) {
        self.evenlyPartitionWithCount((int) Math.ceil(self.size() / size))
    }

}

def array = [1, 2, 3, 4, 5, 6, 7]

use (PartitionCategory) {
assert [[1], [2], [3], [4], [5], [6], [7]] == array.evenlyPartitionWithSize(1)
assert [[1, 2], [3, 4], [5, 6], [7]] == array.evenlyPartitionWithSize(2)
assert [[1, 2, 3], [4, 5], [6, 7]] == array.evenlyPartitionWithSize(3)
assert [[1, 2, 3, 4], [5, 6, 7]] == array.evenlyPartitionWithSize(4)
assert [[1, 2, 3, 4], [5, 6, 7]] == array.evenlyPartitionWithSize(5)
assert [[1, 2, 3, 4], [5, 6, 7]] == array.evenlyPartitionWithSize(6)
assert [[1, 2, 3, 4, 5, 6, 7]] == array.evenlyPartitionWithSize(7)
}
Pierre-David Belanger
  • 1,004
  • 1
  • 11
  • 19