从Groovy中的值组合构建地图列表

时间:2019-01-03 18:06:12

标签: groovy combinations

我想对包含值列表的HashMap进行转换,以生成具有单个值的所有组合。

示例

Suma: <xsl:value-of select="sum(@price)"/>

预期结果是

hm = [x : [1,2], y : ['a','b'] ]

到目前为止,我想出了这种方法

res = [ [x: 1, y : 'a'],
        [x: 1, y : 'b'],
        [x: 2, y : 'a'], 
        [x: 2, y : 'b']   
]

这可行,但是取决于HashMap中键的名称和数量,因此

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

我必须重写为

hm = [u : [1,2], w : ['a','b'] , z : ['X','Y']]

是否存在所有密钥名称和数字的通用解决方案?

2 个答案:

答案 0 :(得分:3)

您可以将闭包传递给.combinations()方法以转换当前组合。然后,您可以使用[[a,b,c], [1,2,3]].transpose()来将两个列表中的值“压缩”在一起(例如,下例中的[[a,1],[b,2],[c,3]]),然后可以使用.collectEntries()将此类对的列表转换为映射。 / p>

考虑以下示例:

def hm = [x : [1,2], y : ['a','b'] ]

def combs = hm.values().combinations { args ->
    [hm.keySet().asList(), args].transpose().collectEntries { [(it[0]): it[1]]}
}

combs.each {
    println it
}

输出:

[x:1, y:a]
[x:2, y:a]
[x:1, y:b]
[x:2, y:b]

现在,我们可以在输入映射中添加另一个键,该代码将按预期工作:

def hm = [x : [1,2], y : ['a','b'], z: ['X','Y'] ]

def combs = hm.values().combinations { args ->
    [hm.keySet().asList(), args].transpose().collectEntries { [(it[0]): it[1]]}
}

combs.each {
    println it
}

输出:

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

使代码更加优雅之后的最后一个示例可能看起来像这样:

def hm = [z : [2,1], y : ['a','b'], x: ['C','B']]

def values = hm.values()
def keys = hm.keySet().toList()

def map = values.combinations { args ->
    [keys, args].transpose().collectEntries { [(it[0]): it[1]]}
}

println map

它打印:

[[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()

答案 1 :(得分:2)

您可以使用键组合和值组合:

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
}

根据提供的输入将result设置为[[x:1, y:a], [x:2, y:a], [x:1, y:b], [x:2, y:b]]

简单的逻辑是:找到键/值对的所有组合,然后对每一对,组合值以保持原始键/值对的顺序。

这适用于动态输入图。

给出hm = [x : [1, 2], y : ['a', 'b'], z: ['e', 'f']],结果为:

[[x:1, y:a, z:e], 
 [x:2, y:a, z:e], 
 [x:1, y:b, z:e], 
 [x:2, y:b, z:e], 
 [x:1, y:a, z:f], 
 [x:2, y:a, z:f], 
 [x:1, y:b, z:f], 
 [x:2, y:b, z:f]]