如何在Groovy中将列表拆分为大小相等的列表?

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

提问人:Geo 提问时间:5/28/2010 最后编辑:raffianGeo 更新时间:3/28/2018 访问量:33894

问:

如果我有这个:

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

是否有一些内置的允许我这样做(或类似的东西):

array.split(2)

并获取:

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

?

列出 groovy 内置

评论

5赞 tim_yates 2/10/2012
从 groovy 1.8.6 开始,您可以在列表上使用 collate 方法

答:

4赞 Chris Dail 5/28/2010 #1

没有内置的东西可以做到这一点,但写起来并不难:

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

评论

2赞 sbglasius 11/3/2010
右侧可以定义为 right = array[mid..-1] (Groovy 方式!
22赞 Ted Naleid 5/28/2010 #2

我同意 Chris 的观点,即 groovy 中没有内置任何东西来处理这个问题(至少对于超过 2 个分区),但我将您的问题解释为提出与他不同的东西。这是一个实现,它满足了我认为您的要求:

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)

评论

0赞 Geo 5/28/2010
是的。这就是我一直在寻找的。昨晚我写了自己的。谢谢!
0赞 raffian 3/3/2012
@Ted 在某些情况下,此函数可能存在并发问题,但很容易解决,stackoverflow.com/questions/9536552/...
3赞 Christoph Metzendorf 5/28/2010 #3

下面是一个替代版本,它使用 Groovy 的动态功能向 List 类添加一个拆分方法,该方法执行您的预期操作:

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)
87赞 tim_yates 5/28/2010 #4

编辑从 groovy 1.8.6 开始,您可以在列表上使用 collate 方法

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

另一种使用 inject 和 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)

编辑:修复了空列表的问题

17赞 benkiefer 6/1/2012 #5

查看 groovy 1.8.6。List 上有一种新的 collate 方法。

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.

有关更多信息,请查看 Groovy List 文档,因为还有其他几个参数为您提供了一些其他选项,包括删除其余部分。

1赞 devside 9/26/2012 #6
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
}
0赞 Pierre-David Belanger 1/12/2013 #7

这个问题很老,但无论如何,我想分享一下我想出的将列表拆分为相同大小的列表的方法。

list.collate很棒,但对我不起作用,因为我需要平均分配列表。

我在哪里工作:

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)
}
2赞 Mark 6/21/2013 #8

我知道这已经非常老了 - 但对于那些希望将列表拆分为相等分区(有余数)的人来说,并且您错过了 Tim 对原始帖子的评论,最新的 groovy 方法是自 Groovy 1.8.6 以来一直可用的 List 对象的 collate() 方法。

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)
9赞 Paresh 2/6/2015 #9

我正在寻找同样的问题,我发现列表的方法非常有用。collate()

array.collate(2)

这是文档的链接。