我有一个列表,我想通过marketName和commodityName按列表价格分组: 例如[“Terra”,“Wheat”,1000.0] - “Terra”是市场名称,“Wheat”是商品名称,1000.0是价格
def marketCommodityGroup = [
["Merkato", "Wheat", 1000.0],
["Shola", "Wheat", 1875.0],
["Merkato", "Barley", 5000.0],
["Merkato", "Wheat", 1000.0],
["Merkato", "Wheat", 1500.0]
]
我希望输出为:
[
["Merkato": ["Wheat" : [1000.0, 1000.0, 1500.0]]],
["Merkato": ["Barley": [5000.0]]],
["Shola": ["Wheat": [1875.0]]]
]
答案 0 :(得分:8)
好的,这是一种做法。
def mapped = marketCommodityGroup.groupBy {
[(it[0]) : it[1]]
}.collect { k,v ->
def grouping = k.find { true }
def prices = v.inject([]) { acc,val -> acc + val[2] }
[ (grouping.key) , [ (grouping.value) : prices ] ]
}.sort { left, right ->
right[0] <=> left[0]
}.collect {
[(it[0]) : it[1] ]
}
groupBy
完全你说的是什么,它按市场名称和商品名称分组collect
创建了不包含最终k:v
关联的有用结构:
grouping
是密钥映射拆分中的唯一条目,以便可以将其重新排序为所需的格式prices
完成了非常方便的inject
,这是Groovy等效的函数式语言中的fold left
操作sort
用于翻转您指定的顺序 - 必须询问实际逻辑是什么,以便您可以替换它collect
执行最终地图分配以获取确切的所需表单是的,它有点密集且神奇,但你总是可以用正确的描述性名称将闭包移到defs。
答案 1 :(得分:3)
[编辑:现在返回原始问题的地图列表]
受到Vamsi Krishna答案的影响,但被链式withDefault
:
def marketCommodityGroup = [
["Terra", "Wheat", 1000.0],
["Shola", "Wheat", 1875.0],
["Terra", "Barley", 5000.0],
["Terra", "Wheat", 1000.0],
["Terra", "Wheat", 1500.0]
]
def marketCommodityMap = [:].withDefault{ [:].withDefault{ [:].withDefault {[]} } }
// map looks like
// ["Terra-Wheat": ["Terra": ["Wheat": [1000.0 ...], "Barley": [5000.0] ]]]
// but we will discard the outer compound key
marketCommodityGroup.each { market, commodity, price ->
marketCommodityMap["${market}-${commodity}"][market][commodity] << price
}
def listOfMaps = marketCommodityMap.values()
println listOfMaps
答案 2 :(得分:3)
另一个版本只是为了好玩; - )
def marketCommodityGroup = [ [ "Terra", "Wheat", 1000.0 ],
[ "Shola", "Wheat", 1875.0 ],
[ "Terra", "Barley", 5000.0 ],
[ "Terra", "Wheat", 1000.0 ],
[ "Terra", "Wheat", 1500.0 ] ]
def group( tree, data ) {
if( data.size() > 2 ) { group( tree."${data.head()}", data.tail() ) }
else {
if( !tree."${data.head()}" ) tree."${data.head()}" = []
tree."${data.head()}" << data[ -1 ]
}
}
def grouped = { [:].withDefault{ owner.call() } }()
marketCommodityGroup.each {
group( grouped, it )
}
assert grouped == ['Terra':['Wheat':[1000.0, 1000.0, 1500.0], 'Barley':[5000.0]],
'Shola':['Wheat':[1875.0]]]
答案 3 :(得分:1)
这可能会有所帮助:
def marketCommodityGroup = [["Terra", "Wheat", 1000.0],
["Shola", "Wheat", 1875.0],
["Terra", "Barely", 5000.0],
["Terra", "Wheat", 1000.0],
["Terra", "Wheat", 1500.0]]
def marketMap = [:].withDefault{[:]}
def commodityMap = [:].withDefault {[]}
marketCommodityGroup.each{ market, comm, price ->
commodityMap[comm].add(price)
}
println("commodityMap: "+commodityMap)
marketCommodityGroup.each{ market, comm, price ->
marketMap[market][comm] = commodityMap[comm]
}
println("MarketMap: "+marketMap)
输出:
commodityMap: [Wheat:[1000.0, 1875.0, 1000.0, 1500.0], Barely:[5000.0]]
MarketMap: [Terra:[Wheat:[1000.0, 1875.0, 1000.0, 1500.0], Barely:[5000.0]], Shola:[Wheat:[1000.0, 1875.0, 1000.0, 1500.0]]]
答案 4 :(得分:1)
def expected = [
["Terra": ["Wheat" : [1000.0, 1000.0, 1500.0]]],
["Terra": ["Barley": [5000.0]]],
["Shola": ["Wheat": [1875.0]]]
]
assert expected == marketCommodityGroup
.groupBy([{it[0]}, {it[1]}]) //Grouping based on 2 keys
.collectEntries{key, val->
[key, val.collectEntries{k, v -> //Collect entries
[k, v.collect{it[2]}.sort()]}] //Sorted price
}.inject([]){list, key, val -> //To transform result as a list
val.each{k, v -> list << [(key): [(k): v]]}
list
}
如果你只需要数据的地图表示,那么不使用注入,你会得到:
[
'Terra':['Wheat':[1000.0, 1000.0, 1500.0], 'Barley':[5000.0]],
'Shola':['Wheat':[1875.0]]
]