Categories
Mastering Development

Groovy – Merge/Group By List of Maps

I have a list of maps that follows the structure 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"]]

I have been trying to build something that would output a list in a similar structure as the input, but merged:

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"]]

Notice how Oct / Nov of FY19 both ultimately had the same accounts, so they were grouped together (this isn’t super important if it can’t be done)

I have tried several iterations here but every time I go down a rabbit hole I get further away from a "groovy" solution. Below is what I have :

List lstDims = ["Year","Period","Account"]
List lstGroupBy1 = ["Year","Period"]
List lstGroupBy2 = lstDims - lstGroupBy1
List<Map<String,List<String>>> lstOut = []
def result = lstData.groupBy{o -> lstGroupBy1.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 -> lstGroupBy2.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

A two issues I am having with this

  1. it doesn’t feel very "groovy" but I am still relatively new to groovy so what do I know
  2. I have to "hard code" the keys within in the groupBy closure : .groupBy{"${it.Year}${it.Period}"} — I can’t figure out a way to pass it 1 or more keys to group by on.

In regards to #2 above I will have a list of keys to group by when this code is executed, but when I can’t figure out how to a I use this in the .groupBy{sGroupBy} – I was trying something like below

EDIT —
Figured out #2, not sure if it is the best way, but it works

Leave a Reply

Your email address will not be published. Required fields are marked *