Groovy groupBy для нескольких свойств и извлечения только значения - PullRequest
0 голосов
/ 10 мая 2018

Имея список элементов:

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, который будет более гибким?

EDIT:

Под более чем 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 вызовов, которые станут нечитаемыми.

1 Ответ

0 голосов
/ 12 мая 2018

Я нашел точное решение проблемы с помощью метода Map s withDefault и рекурсивных вызовов 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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...