从Groovy中的值组合构建映射列表
我想转换一个包含值列表的HashMap,以生成具有单个值的所有组合 范例从Groovy中的值组合构建映射列表,groovy,combinations,Groovy,Combinations,我想转换一个包含值列表的HashMap,以生成具有单个值的所有组合 范例 hm = [x : [1,2], y : ['a','b'] ] 预期结果是 res = [ [x: 1, y : 'a'], [x: 1, y : 'b'], [x: 2, y : 'a'], [x: 2, y : 'b'] ] 到目前为止,我提出了这种看法 println hm.values().combinations().collect{[x:it[0],
hm = [x : [1,2], y : ['a','b'] ]
预期结果是
res = [ [x: 1, y : 'a'],
[x: 1, y : 'b'],
[x: 2, y : 'a'],
[x: 2, y : 'b']
]
到目前为止,我提出了这种看法
println hm.values().combinations().collect{[x:it[0],y:it[1]]}
[[x:1, y:a], [x:2, y:a], [x:1, y:b], [x:2, y:b]]
这是可行的,但取决于HashMap中键的名称和数量,因此
hm = [u : [1,2], w : ['a','b'] , z : ['X','Y']]
我必须重写的是
println hm.values().combinations().collect{[u:it[0],w:it[1],z:it[2]]}
所有键名和数字是否都有通用解决方案?您可以将闭包传递给
.combines()
方法以转换当前组合。然后,您可以使用[[a,b,c],[1,2,3]]].transpose()
将两个列表中的值“zips”在一起(例如,以下示例中的[[a,1],[b,2],[c,3]]
),您可以使用.collectEntries()
将这些对的列表转换为一个映射
考虑以下示例:
defhm=[x:[1,2],y:['a','b']]
def combs=hm.values().组合{args->
[hm.keySet().asList(),args].transpose().collectEntries{[(it[0]):it[1]}
}
梳子{
打印它
}
输出:
[x:1, y:a]
[x:2, y:a]
[x:1, y:b]
[x:2, y:b]
[x:1, y:a, z:X]
[x:2, y:a, z:X]
[x:1, y:b, z:X]
[x:2, y:b, z:X]
[x:1, y:a, z:Y]
[x:2, y:a, z:Y]
[x:1, y:b, z:Y]
[x:2, y:b, z:Y]
现在,我们可以向输入映射添加另一个键,代码将按预期工作:
defhm=[x:[1,2],y:['a','b',z:['x','y']]
def combs=hm.values().组合{args->
[hm.keySet().asList(),args].transpose().collectEntries{[(it[0]):it[1]}
}
梳子{
打印它
}
输出:
[x:1, y:a]
[x:2, y:a]
[x:1, y:b]
[x:2, y:b]
[x:1, y:a, z:X]
[x:2, y:a, z:X]
[x:1, y:b, z:X]
[x:2, y:b, z:X]
[x:1, y:a, z:Y]
[x:2, y:a, z:Y]
[x:1, y:b, z:Y]
[x:2, y:b, z:Y]
使代码更加优雅后的最后一个示例可能如下所示:
defhm=[z:[2,1],y:['a','b',x:['C','b']]
def值=hm.值()
def keys=hm.keySet().toList()
def map=values.compositions{args->
[keys,args].transpose().collectEntries{[(it[0]):it[1]}
}
println图
它打印:
[[z:2, y:a, x:C], [z:1, y:a, x:C], [z:2, y:b, x:C], [z:1, y:b, x:C], [z:2, y:a, x:B], [z:1, y:a, x:B], [z:2, y:b, x:B], [z:1, y:b, x:B]]
值和键的顺序
关于键和值排序的另一个注释。Groovy使用的默认映射实现是LinkedHashMap
,它保证了条目的顺序(它们被添加的顺序)。这意味着:
返回一个map.values()
LinkedHashMap$LinkedValues
返回一个map.keySet()
LinkedHashMap$LinkedKeySet
在我们的示例中,我们必须将
keys
变量定义为hm.keySet()。然后,您可以使用[[a,b,c],[1,2,3]]].transpose()
将两个列表中的值“zips”在一起(例如,以下示例中的[[a,1],[b,2],[c,3]]
),您可以使用.collectEntries()
将这些对的列表转换为一个映射
考虑以下示例:
defhm=[x:[1,2],y:['a','b']]
def combs=hm.values().组合{args->
[hm.keySet().asList(),args].transpose().collectEntries{[(it[0]):it[1]}
}
梳子{
打印它
}
输出:
[x:1, y:a]
[x:2, y:a]
[x:1, y:b]
[x:2, y:b]
[x:1, y:a, z:X]
[x:2, y:a, z:X]
[x:1, y:b, z:X]
[x:2, y:b, z:X]
[x:1, y:a, z:Y]
[x:2, y:a, z:Y]
[x:1, y:b, z:Y]
[x:2, y:b, z:Y]
现在,我们可以向输入映射添加另一个键,代码将按预期工作:
defhm=[x:[1,2],y:['a','b',z:['x','y']]
def combs=hm.values().组合{args->
[hm.keySet().asList(),args].transpose().collectEntries{[(it[0]):it[1]}
}
梳子{
打印它
}
输出:
[x:1, y:a]
[x:2, y:a]
[x:1, y:b]
[x:2, y:b]
[x:1, y:a, z:X]
[x:2, y:a, z:X]
[x:1, y:b, z:X]
[x:2, y:b, z:X]
[x:1, y:a, z:Y]
[x:2, y:a, z:Y]
[x:1, y:b, z:Y]
[x:2, y:b, z:Y]
使代码更加优雅后的最后一个示例可能如下所示:
defhm=[z:[2,1],y:['a','b',x:['C','b']]
def值=hm.值()
def keys=hm.keySet().toList()
def map=values.compositions{args->
[keys,args].transpose().collectEntries{[(it[0]):it[1]}
}
println图
它打印:
[[z:2, y:a, x:C], [z:1, y:a, x:C], [z:2, y:b, x:C], [z:1, y:b, x:C], [z:2, y:a, x:B], [z:1, y:a, x:B], [z:2, y:b, x:B], [z:1, y:b, x:B]]
值和键的顺序
关于键和值排序的另一个注释。Groovy使用的默认映射实现是LinkedHashMap
,它保证了条目的顺序(它们被添加的顺序)。这意味着:
map.values()
返回一个LinkedHashMap$LinkedValues
map.keySet()
返回一个LinkedHashMap$LinkedKeySet
在我们的示例中,我们必须将keys
变量定义为hm.keySet().toList()
,这仅仅是因为transpose()
方法需要一个列表。您可以使用键的组合和值的组合:
def result = []
hm.entrySet().eachCombination { combination ->
combination.collect{it.value}
.eachCombination {
def entry = [:]
for(int i = 0; i < hm.size(); i++) {
entry.put(combination[i].key, it[i])
}
result << entry
}
println result
}
可以使用键的组合和值的组合:
def result = []
hm.entrySet().eachCombination { combination ->
combination.collect{it.value}
.eachCombination {
def entry = [:]
for(int i = 0; i < hm.size(); i++) {
entry.put(combination[i].key, it[i])
}
result << entry
}
println result
}
魔术让我花点时间了解一下,或者看看是否有其他解决方案,我会接受;)很好的解决方案。真的很喜欢你设法让它保持声明性的方式!如何保证args
中的值顺序与keySet().asList()中的值顺序匹配?好像它在工作,我只是不知道怎么做,因为keySet()
是无序的,我认为values()
也是无序的。你试过不按字母顺序排列的键名吗?@billjamesdev很好<代码>[z:1,a:['a','b']]
工作正常,因此可能*两个列表都是无序的,但顺序相同*(?)@SzymonStepniak让我接受它,还是类似于SELECT
而不使用orderby
,可以长期正常工作,但在一些RDBM升级之后,预期的顺序可能会改变?@MarmiteBomber@billjamesdev Groovy使用的默认映射实现是LinkedHashMap
,因此,条目的顺序定义了值和键的顺序。还值得一提的是,hm.values()
返回一个LinkedHashMap$LinkedValues
,而hm.keySet()
返回一个LinkedHashMap$LinkedKeySet
。两者都保证顺序(由条目顺序定义)。如果您正在寻找不同的排序,您可能希望将TreeMap
与自定义比较器一起使用。然而,LinkedHashMap
中元素的顺序是确定的,因此您不必担心任何随机性或其他问题。神奇!让我花点时间来理解它和/或看看是否有其他解决方案,我很高兴