当我在filterKeys
上使用mapValues
或Map
来创建新的Map
时,我传递给这些方法的函数似乎每次都会被执行我使用新的Map
。他们不应该只执行一次来生成新的Map
?
在此示例中,查看println
多次发生的情况。
// printlns happen when creating the map
scala> val myMap = Map(1 -> 1, 2 -> 2, 3 -> 3).filterKeys { i =>
println(s"filterKeys$i")
i < 5
}.mapValues { i =>
println(s"mapValues$i")
i + 1
}
filterKeys1
mapValues1
filterKeys2
mapValues2
filterKeys3
mapValues3
myMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4)
// printlns happen again!
scala> myMap.toString()
filterKeys1
mapValues1
filterKeys2
mapValues2
filterKeys3
mapValues3
res29: String = Map(1 -> 2, 2 -> 3, 3 -> 4)
// and again!
scala> myMap + (4 -> 5)
filterKeys1
mapValues1
filterKeys2
mapValues2
filterKeys3
mapValues3
res30: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5)
我希望行为与.map()
相同。传递给map的函数只为每个项目运行一次,并且在将来使用生成的映射时不再运行:
// printlns happen when creating the map
scala> val myMap = Map(1 -> 1, 2 -> 2, 3 -> 3).map { i =>
println(s"map$i")
i
}
map(1,1)
map(2,2)
map(3,3)
myMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2, 3 -> 3)
// printlns not run again :)
scala> myMap.toString
res32: String = Map(1 -> 1, 2 -> 2, 3 -> 3)
答案 0 :(得分:1)
scaladocs for mapValues
和filterKeys
都提到它们会返回包含原始地图而不复制任何元素的结果地图。您可以在源代码中看到mapValues
返回MappedValues
的实例,该实例会针对每次重复的foreach
,iterator
和get
调用重新运行您的函数。
由于此行为与.map()
不一致,因此可以打开票证SI-4776重命名方法或更改其返回类型以使其更加明显,但票证已打开很长时间,所以不要指望这种行为很快就会改变。
要解决此问题,您可以在使用这些方法强制创建新.view.force
之后附加Map
,或者只使用.map()
代替.mapValues()
和.filter()
代替.filterKeys()
。以下是附加.view.force
的示例:
// printlns happen when creating the map
scala> val myMap = Map(1 -> 1, 2 -> 2, 3 -> 3).filterKeys { i =>
println(s"filterKeys$i")
i < 5
}.mapValues { i =>
println(s"mapValues$i")
i + 1
}.view.force
filterKeys1
mapValues1
filterKeys2
mapValues2
filterKeys3
mapValues3
myMap: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4)
// no printlns when the Map is used again!
scala> myMap.toString
res40: String = Map(1 -> 2, 2 -> 3, 3 -> 4)