Groovy在迭代地图时修改地图元素

时间:2014-10-14 07:26:01

标签: list groovy map

我需要在迭代地图时修改地图元素,在我的情况下减去一些元素(列表)。像这样:

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]]。我做错了什么?由于初始地图​​相当大,我不想用较少的元素构建另一个地图(结果地图)。

3 个答案:

答案 0 :(得分:7)

直接在地图上工作:

a.keySet().each{
    a[it]-=b
}

在您的代码中,您将结果分配给局部变量。

如果您对可能会考虑使用removeAll()或通过迭代bremove()每个更改量而感到担忧。那些改变了清单。

答案 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