首页 > 解决方案 > 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"]]

请注意 FY19 的 10 月 / 11 月最终如何拥有相同的帐户,因此它们被分组在一起(如果无法完成,这并不重要)

我在这里尝试了几次迭代,但每次我进入兔子洞时,我都会远离“常规”解决方案。以下是我所拥有的:

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 闭包中的键进行“硬编码”:.groupBy{"${it.Year}${it.Period}"}- 我想不出一种方法来传递一个或多个键来分组。

关于上面的#2,我将有一个键列表,以便在执行此代码时进行分组,但是当我无法弄清楚如何使用它时.groupBy{sGroupBy}- 我正在尝试类似下面的东西

编辑—— 想出了#2,不确定它是否是最好的方法,但它有效

标签: groovyhashmapmergemap

解决方案


这是一个相当棘手的...

可以这样做:

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
   }
}

不确定它是否比你的更好


推荐阅读