我需要在迭代地图时修改地图元素,在我的情况下减去一些元素(列表)。像这样:
def a = [
1: [1, 2, 3],
2: [3, 2, 4],
3: [3, 2, 4],
4: [5, 2, 1],
]
def b = [3]
println a
a.values().each{ tr ->
tr = tr - b
}
println a
a
地图未发生变化。结果是:
[1:[1, 2, 3], 2:[3, 2, 4], 3:[5, 3, 1], 4:[5, 2, 1]]
[1:[1, 2, 3], 2:[3, 2, 4], 3:[5, 3, 1], 4:[5, 2, 1]]
但是,我希望结果为[1:[1, 2], 2:[2, 4], 3:[5, 1], 4:[5, 2, 1]]
。我做错了什么?由于初始地图相当大,我不想用较少的元素构建另一个地图(结果地图)。
答案 0 :(得分:7)
直接在地图上工作:
a.keySet().each{
a[it]-=b
}
在您的代码中,您将结果分配给局部变量。
如果您对可能会考虑使用removeAll()
或通过迭代b
和remove()
每个更改量而感到担忧。那些改变了清单。
答案 1 :(得分:1)
或者您可以使用collectEntries
:
def a = [
1: [1, 2, 3],
2: [3, 2, 4],
3: [3, 2, 4],
4: [5, 2, 1],
]
def b = [3]
a = a.collectEntries { k, v -> [k, v - b] }
答案 2 :(得分:1)
首先,我建议使用普通的,纯粹的Java List.remove(Object)
而不是Groovy的List.minus(List)
。那就是改变界限:
def b = [3]
和
tr = tr - b
进入以下内容:
def b = 3
和
tr.remove((Object)b)
前一对语句的问题是表达式tr - b
创建了一个新的列表对象。此列表分配给局部变量tr
。同时原始列表,即驻留在Map中的列表,在分配之前tr
的原始值保持不变。
显式List.remove(Object)
方法,但不是" Groovy"作为减法,在原始列表上运行而不创建新列表。除了产生正确的结果之外,该技术还具有不为每个映射条目实例化新列表的优点。
注意有必要明确地将b
投射到Object
。 Groovy执行动态分派以解决运算符重载问题。如果没有强制类型转换,即使静态类型b
已经Object
,Groovy也会检测到b
是一个整数并调用List.remove(int)
而不是List.remove(Object)
,哪会失败。演员阵容中,Groovy有足够的暗示做正确的事情。
<小时/> 其次,我建议使用
Map.each
代替Map.values()
链接到List.each
。因此,替换这一行:
a.values().each { tr ->
以下内容:
a.each { key, tr ->
前一个语句导致映射实例化包含所有值的列表,而后一个语句则不实例化。虽然实际的&#34;值&#34;在第一种情况下,与地图中的值相同,您曾说过地图太大,以至于您不想创建一个全新的地图。所以我同样假设你不想从地图的价值对象中创建一个完整的列表。
<小时/> 如果您遵循这些建议,您的最终代码应如下所示:
def a = [
1: [1, 2, 3],
2: [3, 2, 4],
3: [3, 2, 4],
4: [5, 2, 1],
]
def b = 3
println a
a.each{ k, v ->
v.remove((Object)b)
}
println a