Groovy - объединение / группировка по списку карт
У меня есть список карт, соответствующих структуре List<Map<String,List<String>>>
List<Map<String,List<String>>> lstData = []
lstData << ["Year":["FY19"],"Period":["Oct"],"Account":["A1000","A1001"]]
lstData << ["Year":["FY19"],"Period":["Oct"],"Account":["A1001","A1002"]]
lstData << ["Year":["FY19"],"Period":["Nov"],"Account":["A1000","A1001","A1002"]]
lstData << ["Year":["FY19"],"Period":["Dec"],"Account":["A1000","A1002"]]
lstData << ["Year":["FY20"],"Period":["Jan"],"Account":["A1000","A1003"]]
Я пытался создать что-то, что выводило бы список в структуре, аналогичной входной, но объединенной:
List<Map<String,List<String>>> lstTarget = []
lstTarget << ["Year":["FY19"],"Period":["Oct","Nov"],"Account":["A1000","A1001","A1002"]]
lstTarget << ["Year":["FY19"],"Period":["Dec"],"Account":["A1000","A1002"]]
lstTarget << ["Year":["FY20"],"Period":["Jan"],"Account":["A1000","A1003"]]
Обратите внимание, как в октябре / ноябре 2019 финансового года у обоих в конечном итоге были одни и те же учетные записи, поэтому они были сгруппированы вместе (это не очень важно, если это невозможно сделать)
Я пробовал здесь несколько итераций, но каждый раз, когда я спускаюсь в кроличью нору, я все больше отдаляюсь от "отличного" решения. Вот что у меня есть:
List lstDims = lstData[0].keySet() as List
List<Map<String,List<String>>> lstOut = []
def result = lstData.groupBy{o -> lstDims.dropRight(1).collect{o."$it"}}.values()
result.each { item ->
lstOut << item*.keySet().flatten().unique().collectEntries{
[(it): item*.get(it).findAll().flatten().unique()]
}
}
println lstOut
// Gets a List Like Below
/*
[
[Year:[FY19], Period:[Oct], Account:[A1000, A1001, A1002]],
[Year:[FY19], Period:[Nov], Account:[A1000, A1001, A1002]],
[Year:[FY19], Period:[Dec], Account:[A1000, A1002]],
[Year:[FY20], Period:[Jan], Account:[A1000, A1003]]
]
*/
// Repeat to group back by account, ultimately providing the Target List:
result = lstOut.groupBy{o -> lstDims.takeRight(1).collect{o."$it"}}.values()
lstOut = []
result.each { item ->
lstOut << item*.keySet().flatten().unique().collectEntries{
[(it): item*.get(it).findAll().flatten().unique()]
}
}
println lstOut
assert lstOut == lstTarget
У меня есть две проблемы с этим
- это не кажется очень "заводным", но я все еще относительно новичок в groovy, так что я знаю
- Мне нужно "жестко закодировать" ключи внутри группы путем закрытия:
.groupBy{"${it.Year}${it.Period}"}
- Я не могу придумать способ передать ему 1 или несколько ключей для группировки.
Что касается пункта 2 выше, у меня будет список ключей для группировки при выполнении этого кода, но когда я не могу понять, как это сделать, я использую его в .groupBy{sGroupBy}
- Я пробовал что-то вроде ниже
РЕДАКТИРОВАТЬ - Выяснил #2, не уверен, что это лучший способ, но он работает
1 ответ
Довольно запутанный, что...
Вы могли сделать это:
List<Map<String,List<String>>> lstData = []
lstData << ["Year":["FY19"],"Period":["Oct"],"Account":["A1000","A1001"]]
lstData << ["Year":["FY19"],"Period":["Oct"],"Account":["A1001","A1002"]]
lstData << ["Year":["FY19"],"Period":["Nov"],"Account":["A1000","A1001","A1002"]]
lstData << ["Year":["FY19"],"Period":["Dec"],"Account":["A1000","A1002"]]
lstData << ["Year":["FY20"],"Period":["Jan"],"Account":["A1000","A1003"]]
lstData.groupBy { it.Year + it.Period }.collect { k, v ->
v.tail().inject(v.head()) { r, c -> r.Account = (r.Account + c.Account).unique(); r }
}.groupBy { it.Account }.collect { k, v ->
v.tail().inject(v.head()) { r, c ->
r.Year = (r.Year + c.Year).unique()
r.Period = (r.Period + c.Period).unique()
r
}
}
Не уверен, что он лучше твоего.