开发者

How to split a list into equal sized lists in Groovy?

开发者 https://www.devze.com 2023-01-01 21:22 出处:网络
If I have this: def a开发者_JAVA技巧rray = [1,2,3,4,5,6] Is there some built-in which allows me to do this ( or something similar ):

If I have this:

def a开发者_JAVA技巧rray = [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]]

?


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


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)


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.


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.


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


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)


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)


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
}


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)
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号