我有一组看起来像这样的地图:
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]]
我正在尝试获得一个看起来像这样的结果,该结果对唯一的key1和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,它有点像示例here。然而,看起来如果联合收回地图,它想要进一步合并。
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)
}
答案 0 :(得分: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"
}