scala - `filterKeys` 和 `mapValues` 被执行多次

标签 scala scala-collections

当我在 Map 上使用 filterKeysmapValues 来创建新的 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 的函数,仅对每个项目运行一次,并且在将来使用结果 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)

最佳答案

scaladocs for mapValuesfilterKeys两者都提到它们返回一个结果映射,该映射包装原始映射而不复制任何元素。源码中可以看到mapValues返回 MappedValues 的实例它会为每次重复的 foreachiteratorget 调用重新运行您的函数。

因为这个行为与.map()不一致,所以有ticket SI-4776 open 来重命名方法或更改其返回类型以使这一点更加明显,但是票证已经开放很长时间了,因此不要指望这种行为很快就会改变。

更新:自 Scala 2.13 起,这些方法已被弃用,并计划在未来版本中修复:

(Since version 2.13.0) Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).

除了建议的 view.mapValues(f).toMap 之外,您还可以使用 transform 而不是 mapValues 来解决此问题和 filter 而不是 filterKeys:

val myMap = Map(1 -> 1, 2 -> 2, 3 -> 3).filter { case (i, _) => 
    println(s"filterKeys$i")
    i < 5
  }.transform { (_, i) =>
    println(s"mapValues$i")
    i + 1
  }

// no printlns when the Map is used again!
myMap.toString

关于scala - `filterKeys` 和 `mapValues` 被执行多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43173795/

相关文章:

scala - Scala 中二维数组的类型不匹配错误

scala - Spark-rdd 操作数据

scala - 二维数组作为函数

scala - Spark 中的用户定义聚合函数 UDAF 何时发生合并

scala - 混入嵌套在对象中的特征时出现 AbstractMethodError - 仅在编译和导入时

scala - 调用 toArray 时编译器错误

scala - Circe:将隐式编码器移至通用类中

Scala Sets 包含相同的元素,但 SameElements() 返回 false

scala - 如何在 Scala 2.8 中实现集合?

Scala 惯用语从迭代器中找到第一个选项