在Groovy中组合多个映射

时间:2016-02-25 18:09:20

标签: groovy

我有三张地图,一张清单给我一张去年卖车的地图,第二张图给出了六个月卖车的清单 第三张地图给了我上个月卖车的清单。见下文

totalYear = [
    [brand:"BMW"],
    [brand:"BMW"], 
    [brand:"BMW"], 
    [brand:"BMW"], 
    [brand:"BMW"], 
    [brand:"BMW"], 
    [brand:"BMW"], 
    [brand:"mercedes"], 
    [brand:"mercedes"], 
    [brand:"mercedes"]
]

totalSixMonth = [
    [brand:"BMW"], 
    [brand:"BMW"],
    [brand:"BMW"],
    [brand:"mercedes"], 
    [brand:"mercedes"] 
]

totalMonth = [
    [brand:"BMW"], 
    [brand:"mercedes"]                      
]

如何将这些地图组合成一个地图,如

total = [
    [totalMonth:"1", totalSixMonth:"3", totalYear:"7", brand:"BMW"], 
    [totalMonth:"1", totalSixMonth:"2", totalYear:"3", brand:"mercedes"] 
]

我尝试groupBycollect,但他们没有给出正确的结果。谁能帮忙解决这个问题?

2 个答案:

答案 0 :(得分:4)

你可以这样做:

// Something to extract counts
def counts = { input -> input.groupBy { it.brand }.collectEntries { k, v -> [k, v.size()] } }

def result = [totalYear:totalYear, totalSixMonth:totalSixMonth, totalMonth:totalMonth]
    .collectMany { name, list -> // (A)
        counts(list).collect { brand, num -> [(name):num, brand:brand] }
    }
    .groupBy { it.brand } // (B)
    .collect { it.value } // (C)
    .collect {
        it.inject { a, b -> a + b } // (D)
    }

给出结果:

[
    ['totalYear':7, 'brand':'BMW', 'totalSixMonth':3, 'totalMonth':1],
    ['totalYear':3, 'brand':'mercedes', 'totalSixMonth':2, 'totalMonth':1]
]

稍微解释一下,这里的每个阶段的数据是什么样的:

在(A)的collectMany之后,我们有以下形式的数据:

[['totalYear':7, 'brand':'BMW'], ['totalYear':3, 'brand':'mercedes'], ['totalSixMonth':3, 'brand':'BMW'], ['totalSixMonth':2, 'brand':'mercedes'], ['totalMonth':1, 'brand':'BMW'], ['totalMonth':1, 'brand':'mercedes']]

在({B)groupBy之后,这变为:

['BMW':[['totalYear':7, 'brand':'BMW'], ['totalSixMonth':3, 'brand':'BMW'], ['totalMonth':1, 'brand':'BMW']], 'mercedes':[['totalYear':3, 'brand':'mercedes'], ['totalSixMonth':2, 'brand':'mercedes'], ['totalMonth':1, 'brand':'mercedes']]]

然后,我们可以在(C)处丢弃此地图的键,以获取地图列表的列表:

[[['totalYear':7, 'brand':'BMW'], ['totalSixMonth':3, 'brand':'BMW'], ['totalMonth':1, 'brand':'BMW']], [['totalYear':3, 'brand':'mercedes'], ['totalSixMonth':2, 'brand':'mercedes'], ['totalMonth':1, 'brand':'mercedes']]]

对于这些地图列表中的每一个,我们都可以使用inject将它们折叠到(D)的单个地图中,因此我们最终得到的是地图列表和最终结果。

对于相同的结果可能有一个较短的方法,因为这感觉就像它有太多的groupBy调用......

另一种选择,但不会短得多(如果有的话)

def result = [totalYear:totalYear, totalSixMonth:totalSixMonth, totalMonth:totalMonth]
    .collectMany { name, list ->
        list.countBy { it.brand }.collect { brand, count ->
            [(name): count, brand: brand]
        }
    }
    .groupBy { it.brand }.values()*.inject { a, b -> a + b }

答案 1 :(得分:1)

您可以做的第一件事就是将三个Map合并为一个,每个变量都是关键,Map是值。之后,您将需要一系列转换。

def total = [totalYear: totalYear, totalSixMonth: totalSixMonth, totalMonth: totalMonth].collectEntries { label, maps ->
    [(label): maps.countBy { it.brand} ]
}.inject([:]) { result, label, counts -> 
    counts.entrySet().each { entry -> 
        if(!result[entry.key]) result[entry.key] = [:]
        result[entry.key][(label)] = entry.value
    }
    result
}.collect { brand, counts -> [brand: brand] << counts } 

collectEntries()累积总数:

[totalYear:[BMW:7, mercedes:3], totalSixMonth:[BMW:3, mercedes:2], totalMonth:[BMW:1, mercedes:1]]

inject()按品牌分组总数:

[BMW:[totalYear:7, totalSixMonth:3, totalMonth:1], mercedes:[totalYear:3, totalSixMonth:2, totalMonth:1]]

最后,collect()构建了最终列表:

[['brand':'BMW', 'totalYear':7, 'totalSixMonth':3, 'totalMonth':1], ['brand':'mercedes', 'totalYear':3, 'totalSixMonth':2, 'totalMonth':1]]

注意:您要求Map,但演示了ListMap。我参加了演示。