所以基本上我有这样的事情:
[a: ["c","d"], b: ["e","f"]]
Run Code Online (Sandbox Code Playgroud)
每个列表中的项目数量是任意的.如果只有一个项目,则列表不再是列表,而是一个字符串.
我想把它变成:
[ [a:"c", b:"e"], [a:"d",b:"f"] ]
Run Code Online (Sandbox Code Playgroud)
我真的不在乎解决方案是否使用Groovy方法.谢谢你的帮助!
这是另一种方法,我认为不那么模糊,同时仍然相当简洁:
def ml = [a: ["c","d"], b: ["e","f"]]
// Create an empty list that creates empty maps as needed
def lm = [].withDefault{ [:] }
ml.each{ k, values ->
[values].flatten().eachWithIndex { value, index ->
lm[index][k] = value
}
}
assert lm == [[a:"c", b:"e"], [a:"d", b:"f"]]
Run Code Online (Sandbox Code Playgroud)
如果您不想或不能使用withDefault(因为您不希望列表自动增长),那么这也适用:
def ml = [a: ["c","d"], b: ["e","f"]]
def lm = []
ml.each{ k, values ->
[values].flatten().eachWithIndex { value, index ->
lm[index] = lm[index] ?: [:]
lm[index][k] = value
}
}
assert lm == [[a:"c", b:"e"], [a:"d", b:"f"]]
Run Code Online (Sandbox Code Playgroud)
编辑:添加代码以处理列表中未包含的字符串.
注意,给定的技巧([values].flatten().eachWithIndex{...})不一定非常有效.如果速度是必不可少的,那么使用它会稍微快一些,但会牺牲可读性:
(values instanceof List ? values : [values]).eachWithIndex{...}
Run Code Online (Sandbox Code Playgroud)
单行,假设x = [a: ["c","d"], b: ["e","f"]]或x = [a: "b", c: "d"]:
[x*.key, x*.value].transpose()*.combinations().transpose()*.flatten()*.toSpreadMap()
Run Code Online (Sandbox Code Playgroud)
这是如何工作的:
首先,拆分键和值:
[x*.key, x*.value] = [[a, b], [[c, d], [e, f]]]
转置它们以配对键和值:
[[a, b], [[c, d], [e, f]]].transpose() = [[a, [c, d]], [b, [e, f]]]
用于combinations将密钥与其值配对(此处使用的扩展运算符将其应用于每个列表元素).请注意,组合将同时处理两个[a:b]或[a:[b,c]]正确:
[[a, [c, d]], [b, [e, f]]]*.combinations() = [[[a, c], [a, d]], [[b, e], [b, f]]]
转置列表以便我们最终得到abab而不是aabb(虽然有点嵌套):
[[[a, c], [a, d]], [[b, e], [b, f]]].transpose() = [[[a, c], [b, e]], [[a, d], [b, f]]]
展平嵌套列表(再次使用spread来展平嵌套列表,但不是整个列表):
[[[a, c], [b, e]], [[a, d], [b, f]]]*.flatten() = [[a, c, b, e], [a, d, b, f]]
Spread toSpreadMap将此列表转换为地图列表.
[[a, c, b, e], [a, d, b, f]]*.toSpreadMap() = [*:[b:e, a:c], *:[b:f, a:d]]