Grails Groovy中的组和和集合

Grails Groovy中的组和和集合,grails,groovy,Grails,Groovy,我有一个要按月分组的对象集合以及名称和总和: 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-0

我有一个要按月分组的对象集合以及名称和总和:

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实现这一点的最佳方法是什么

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

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时,我最终得到了

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.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() ]
  } ]
}

这里有一个与其他解决方案做相同事情的解决方案,但是使用GPAR并行。可能有一个更严格的解决方案,但这个解决方案确实适用于测试输入

@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"
}

这里有一个与其他解决方案做相同事情的解决方案,但是使用GPAR并行。可能有一个更严格的解决方案,但这个解决方案确实适用于测试输入

@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"
}

@安德烈·斯坦吉斯我无法抗拒关于咀嚼列表和地图的问题-@安德烈·斯坦吉斯我无法抗拒关于咀嚼列表和地图的问题-我不确定这是使用GPAR最严格/最好/最快的方式。如果有人有一个替代的并行解决方案,请把它也贴出来或对此发表评论。我不确定这是使用GPAR的最严格/最好/最快的方法。如果有人有一个替代的并行解决方案,请张贴它也或作出评论这一个。