请考虑以下事项:
val stuff = Map[String, Int]("apple" -> 5, "orange" -> 1, "banana" -> 3, "kiwi" -> 2)
val used = 1
val rest = stuff.mapValues{
case quantity => quantity - used
}.filterNot{
case (fruit, quantity) => quantity == 0
}
结果是
rest : scala.collection.immutable.Map[String,Int] = Map(apple -> 4, banana -> 2, kiwi -> 1)
虽然我不是Scala的专家,但我知道该语言不是懒惰的(与Haskell不同),因此mapValues
将产生一个中间Map
,而后者将作为输入到filterNot
(如果链中还有其他操作,那么。)
如何避免这种无用的中间数据结构?
注意:我知道这个问题可以推广到其他数据结构。这里我使用Map
只是因为它是我在实际代码中使用的数据结构(尽管有其他数据:))
答案 0 :(得分:7)
您可以使用任何集合类的view
方法创建一个集合视图,该视图将懒惰地应用map
和filter
等方法。见http://www.scala-lang.org/archives/downloads/distrib/files/nightly/docs/library/index.html#scala.collection.TraversableLike
答案 1 :(得分:3)
除了@Kim的答案之外,应该注意mapValues
方法实际上不计算中间结果:mapValues
返回视图一张地图。这使其与大多数其他方法不同,包括filterNot
或甚至map
。
一个例子:
val rest = stuff.mapValues {
case quantity =>
println("reading quantity " + quantity)
quantity - used
}
rest("apple")
rest("apple")
打印:
reading quantity 5
reading quantity 5
答案 2 :(得分:3)
这似乎可以解决问题:
object ChainOpsRS
{
val stuff = Map[String, Int]("apple" -> 5, "orange" -> 1, "banana" -> 3, "kiwi" -> 2)
val used = 1
val rest =
stuff.collect {
case (fruit, quantity) if quantity > used => (fruit, quantity - used)
}
def main(args: Array[String]) {
printf("stuff=%s%n", stuff.mkString("{", ", ", "}"))
printf(" rest=%s%n", rest.mkString("{", ", ", "}"))
}
}
运行时会生成此输出:
stuff={apple -> 5, orange -> 1, banana -> 3, kiwi -> 2}
rest={apple -> 4, banana -> 2, kiwi -> 1}