1

我有一组看起来像这样的地图:

def list = [
    [key1: 'ABC', key2: 3, value: 1.01],
    [key1: 'ABC', key2: 4, value: 1.02],
    [key1: 'ABC', key2: 4, value: 1.03],
    [key1: 'DEF', key2: 3, value: 1.04]]

我试图得到一个看起来像这样的结果,它对唯一 k​​ey1 和 key2 值的值进行分组和总结,并产生层次结构。

['ABC':[[key2: 2, value: 1.01]
        [key2: 4, value: 2.05]],   //note values are added
 'DEF':[[key2: 3, value: 1.04]]
]

有很多映射例程只有一个键的示例,但是当使用多个键时,折叠这些例程的最佳方法是什么?

我想到的一个解决方案是使用 groupby 来获取按第一个键分组的列表。然后必须在每个元素的子列表上运行 combine 或 reduce 的问题:

list.parallel
.map{it}
.groupBy{it.key1}

在这一点上,我想减少分组地图的 .value() ,我在链中实际上无法做到这一点

我还尝试使用 combine,它的工作原理有点像这里的示例。然而,看起来如果 combine 得到一张地图,它想进一步组合它。

def result = list.parallel
        .map{[it.key1, it]}
        .combine({-> [:]})  { map, v -> println "$map - $v = ${v.getClass()}"
            map[v.key2] = map[v.key2]?:0 + v.value
            map
        }

然后可以选择只在地图上进行归约,但是归约例程随后变成了一个非常复杂的组合嵌套地图的野兽。所以我想知道是否有更简单的东西,或者我应该运行一个 reduce 例程来组合复杂的映射。

list.parallel
.map{[(it.key1):it]}
.reduce([:]) { a, b ->
   complexMapCombiner(a, b)
}
4

1 回答 1

2

所以这是一个可行的解决方案,但不如我想要的那么优雅。如果有人有更好的东西,请发布答案。

@Grab(group='org.codehaus.gpars', module='gpars', version='1.0.0')

import static groovyx.gpars.GParsPool.*

def list = [
    [key1: 'ABC', key2: 3, value: 1.01],
    [key1: 'ABC', key2: 4, value: 1.02],
    [key1: 'ABC', key2: 4, value: 1.03],
    [key1: 'DEF', key2: 3, value: 1.04]]

withPool {
    def mapInner = { entrylist ->
         withPool{
             entrylist.getParallel()
                 .map{[it.key2, it.value]}
                 .combine(0) {acc, v -> acc + v}.getParallel()
                 .map{[key2: it.key, value: it.value]}.collection
         }
    }

    //for dealing with bug when only 1 list item
    def collectSingle = { entrylist ->
        def first = entrylist[0]
        return [[key2:(first.key2), value:first.value]]
    }

    def result = list.parallel
        .groupBy{it.key1}.getParallel()
        .map{ [(it.key) : (it.value?.size())>1?mapInner.call(it.value):collectSingle.call(it.value) ] }
        .reduce([:]) {a, b -> a + b}


    println "result = $result"
}
于 2013-05-08T01:31:01.797 回答