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

У меня есть две проблемы с этим

  1. это не кажется очень "заводным", но я все еще относительно новичок в groovy, так что я знаю
  2. Мне нужно "жестко закодировать" ключи внутри группы путем закрытия: .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
   }
}

Не уверен, что он лучше твоего.

Другие вопросы по тегам