首页 > 解决方案 > Groovy groupBy 在多个属性上并仅提取值

问题描述

有一个元素列表:

List list =  [
    [category: 'A', name: 'a' value: 10],
    [category: 'A', name: 'b' value: 20],
    [category: 'B', name: 'a' value: 30],
    [category: 'B', name: 'c' value: 40],
    [category: 'B', name: 'd' value: 50],
]

我想将其转换为嵌套地图:

Map map = [
    A: [a: 10, b: 20],
    B: [a: 30, c: 40, d: 50],
]

我想出的唯一解决方案是做这样的事情:

list.groupBy(
    { it.category }, { it.name }
).collectEntries { category, names ->
    [(category): names.collectEntries { name, values ->
        [(name): values.value[0]]
    }]
}

但是,我以后要处理2级以上的嵌套,这种做法是不可行的。

是否有任何巧妙的方法可以在 Groovy 中获得更灵活的正确结果?

编辑:

通过超过 2 层嵌套,我的意思是转换结构,如:

List list =  [
    [category: 'A', subcategory: 'I', group: 'x', name: 'a', value: 10],
    [category: 'A', subcategory: 'I', group: 'y', name: 'b', value: 20],
]

进入:

Map map = [
    A: [I: [
        x: [a: 10],
        y: [b: 20],
    ]],
]

通过添加嵌套(深度),它将需要更多的嵌套collectEntries调用,这将变得不可读。

标签: groovy

解决方案


Map通过使用'swithDefault方法和递归调用,我找到了一个巧妙的解决方案Closure

Map map = { [:].withDefault { owner.call() } }.call()
list.each {
    map[it.category][it.name] = it.value
}

或者对于第二种情况:

Map map = { [:].withDefault { owner.call() } }.call()
list.each {
    map[it.category][it.subcategory][it.group][it.name] = it.value
}

推荐阅读