我有一组对象,我想按月分组,名称和总和:
def things = [
[id:1, name:"fred", total:10, date: "2012-01-01"],
[id:2, name:"fred", total:10, date: "2012-01-03"],
[id:3, name:"jane", total:10, date: "2012-01-04"],
[id:4, name:"fred", total:10, date: "2012-02-11"],
[id:5, name:"jane", total:10, date: "2012-01-01"],
[id:6, name:"ted", total:10, date: "2012-03-21"],
[id:7, name:"ted", total:10, date: "2012-02-09"]
];
我希望输出为:
[
"fred":[[total:20, month:"January"],[total:10, month:"February"]],
"jane":[[total:20,month:"January"]],
"ted" :[[total:10, month:"February"],[total:10, month:"March"]]
]
或类似的东西。使用groovy / grails来实现这一目标的最佳方法是什么?
答案 0 :(得分:3)
以下行
things.inject([:].withDefault { [:].withDefault { 0 } } ) {
map, v -> map[v.name][Date.parse('yyyy-MM-dd', v.date).format('MMMM')] += v.total; map
}
会给你这个结果:
[fred:[January:20, February:10], jane:[January:20], ted:[March:10, February:10]]
(适用于Groovy> = 1.8.7和2.0)
答案 1 :(得分:1)
我最终得到了
things.collect {
// get the map down to name, total and month
it.subMap( ['name', 'total' ] ) << [ month: Date.parse( 'yyyy-MM-dd', it.date ).format( 'MMMM' ) ]
// Then group by name first and month second
}.groupBy( { it.name }, { it.month } ).collectEntries { k, v ->
// Then for the names, collect
[ (k):v.collectEntries { k2, v2 ->
// For each month, the sum of the totals
[ (k2): v2.total.sum() ]
} ]
}
得到与安德烈更短,更好的答案相同的结果; - )
有点短,但还是不太好......
things.groupBy( { it.name }, { Date.parse( 'yyyy-MM-dd', it.date ).format( 'MMMM' ) } ).collectEntries { k, v ->
[ (k):v.collectEntries { k2, v2 ->
[ (k2): v2.total.sum() ]
} ]
}
答案 2 :(得分:0)
这是一个与其他解决方案做同样事情的解决方案,但是并行使用GPars。可能有一个更严格的解决方案,但这个解决方案确实适用于测试输入。
@Grab(group='org.codehaus.gpars', module='gpars', version='1.0.0')
import static groovyx.gpars.GParsPool.*
//def things = [...]
withPool {
def mapInner = { entrylist ->
withPool{
entrylist.getParallel()
.map{[Date.parse('yyyy-MM-dd', it.date).format('MMMM'), it.total]}
.combine(0) {acc, v -> acc + v}
}
}
//for dealing with bug when only 1 list item
def collectSingle = { entrylist ->
def first = entrylist[0]
return [(Date.parse('yyyy-MM-dd', first.date).format('MMMM')) : first.total]
}
def result = things.parallel
.groupBy{it.name}.getParallel()
.map{ [(it.key) : (it.value?.size())>1?mapInner.call(it.value):collectSingle.call(it.value) ] }
.reduce([:]) {a, b -> a + b}
println "result = $result"
}