我有一组对象,我想分成一组集合,其中每个连续的3个元素组都在一个集合中。 例如,如果我有
def l = [1,4,2,4,5,9]
我想把它变成:
def r = [[1,4,2], [4,5,9]]
我现在正在通过迭代集合并将其分解来实现它。但是我需要将这些'组'传递给处理它们的并行化函数。消除这个O(n)会很好预处理工作,只需说出像
这样的内容l.slice(3).collectParallel { subC -> process(subC) }
我在Range类上找到了step方法,但看起来它只对索引起作用。任何聪明的想法?
更新: 我不认为这是引用链接的重复,尽管它非常接近。如下所示,它更像是我正在寻找的迭代器类型的东西..子集合将被传递到GPars collectParallel。理想情况下,我不需要分配整个新集合。
答案 0 :(得分:21)
查看groovy 1.8.6。 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.
请查看Groovy List documentation以获取更多信息,因为还有其他一些参数可以为您提供其他选项,包括删除剩余部分。
就您的并行处理而言,您可以使用gpars浏览列表。
def list = [1, 2, 3, 4, 5]
GParsPool.withPool {
list.collate(2).eachParallel {
println it
}
}
答案 1 :(得分:2)
如果我理解正确,您当前正在将原始集合中的元素复制到子集合中。有关这些方面的更多建议,请查看以下问题的答案:Split collection into sub collections in Groovy
听起来你正在寻找的是一种让子集有效地成为原始集合视图的方式。如果是这种情况,请查看List.subList() method。您可以将索引从0循环到size(),以3为增量(或您选择的任何切片大小),或者您可以获得更好的并构建一个Iterable / List,它将隐藏调用者的详细信息。这是后者的实现,受Ted's answer启发。
class Slicer implements Iterator {
private List backingList
private int sliceSize
private int index
Slicer(List backingList, int sliceSize) {
this.backingList = backingList
this.sliceSize = sliceSize
}
Object next() {
if (!hasNext()) {
throw new NoSuchElementException()
}
def ret
if (index + sliceSize <= backingList.size()) {
ret = backingList.subList(index, index+sliceSize)
} else if (hasNext()) {
ret = backingList.subList(index, backingList.size())
}
index += sliceSize
return ret
}
boolean hasNext() {
return index < backingList.size()
}
void remove() {
throw new UnsupportedOperationException() //I'm lazy ;)
}
}
答案 2 :(得分:1)
我喜欢这两种解决方案,但这是我非常喜欢的第一种解决方案的略微改进版本:
class Slicer implements Iterator {
private List backingList
private int sliceSize
private int index
Slicer(List backingList, int sliceSize) {
this.backingList = backingList;
int ss = sliceSize;
// negitive sliceSize = -N means, split the list into N equal (or near equal) pieces
if( sliceSize < 0) {
ss = -sliceSize;
ss = (int)((backingList.size()+ss-1)/ss);
}
this.sliceSize = ss
}
Object next() {
if (!hasNext()) {
throw new NoSuchElementException()
}
def ret = backingList.subList(index, Math.min(index+sliceSize , backingList.size()) );
index += sliceSize
return ret
}
boolean hasNext() {
return index < backingList.size() - 1
}
void remove() {
throw new UnsupportedOperationException() //I'm lazy ;)
}
List asList() {
this.collect { new ArrayList(it) }
}
List flatten() {
backingList.asImmutable()
}
}
// ======== TESTS
def a = [1,2,3,4,5,6,7,8];
assert [1,2,3,4,5,6,7,8] == a;
assert [[1, 2], [3, 4], [5, 6], [7, 8]] == new Slicer(a,2).asList();
assert [[1,2,3], [4,5,6], [7,8]] == (new Slicer(a,3)).collect { it } // alternative to asList but inner items are subList
assert [3, 2, 1, 6, 5, 4, 8, 7] == ((new Slicer(a,3)).collect { it.reverse() } ).flatten()
// show flatten iterator
//new Slicer(a,2).flattenEach { print it }
//println ""
// negetive slice into N pieces, in this example we split it into 2 pieces
assert [[1, 2, 3, 4], [5, 6, 7, 8]] == new Slicer(a,-2).collect { it as List } // same asList
assert [[1, 2, 3], [4, 5, 6], [7, 8]] == new Slicer(a,-3).asList()
//assert a == (new Slicer(a,3)).flattenCollect { it }
assert [9..10, 19..20, 29..30] == ( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) } )
assert [[9, 10], [19, 20], [29, 30]] == ( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) }.collect { it.flatten() } )
println( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) } )
println( (new Slicer(1..30,2)).findAll { slice -> !(slice[1] % 10) }.collect { it.flatten() } )
答案 3 :(得分:0)
没有内置任何内容可以完全按照你想要的方式执行,但是如果我们@Delegate
调用本机列表的迭代器,我们就可以编写自己的类,它就像一个返回块的迭代器一样工作。寻找:
class Slicer {
protected Integer sliceSize
@Delegate Iterator iterator
Slicer(objectWithIterator, Integer sliceSize) {
this.iterator = objectWithIterator.iterator()
this.sliceSize = sliceSize
}
Object next() {
List currentSlice = []
while(hasNext() && currentSlice.size() < sliceSize) {
currentSlice << this.iterator.next()
}
return currentSlice
}
}
assert [[1,4,2], [4,5,9]] == new Slicer([1,4,2,4,5,9], 3).collect { it }
因为它具有普通迭代器所做的所有方法,所以你可以免费获得groovy语法糖方法,并对任何具有iterator()
方法的方法进行惰性求值,如范围:
assert [5,6] == new Slicer(1..100, 2).find { slice -> slice.first() == 5 }
assert [[9, 10], [19, 20], [29, 30]] == new Slicer(1..30, 2).findAll { slice -> !(slice[1] % 10) }