Scala数据结构:操作链(如mapValues、filter…)和中间结果
考虑以下几点:Scala数据结构:操作链(如mapValues、filter…)和中间结果,scala,Scala,考虑以下几点: 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 } 结果
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
,该中间Map将作为输入传递给filterNot
(如果链中有其他操作,也是如此)
如何避免这种无用的中间数据结构
注:我知道这个问题可以推广到其他数据结构。这里我使用的是Map
,因为这是我在真实代码中使用的数据结构(尽管使用了其他数据:)您可以使用任何集合类的视图
方法来创建集合视图,该视图将延迟应用Map
和过滤器
等方法。参见除了@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
这似乎起到了作用:
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}
我不会认为它没用;很明显,它是有用的。您可能会发现collect
方法在这种情况下非常方便。它使用一个分部函数将map
和filter
组合在一起(PF未处理的情况被过滤掉),这在源代码和内部数据结构方面都更加节省。@RandallSchulz我考虑过collect
,但在我的示例中我没有弄清楚如何使用它。你能把你的评论变成一个答案并告诉我怎么做吗?谢谢有趣!我没有注意到mapValues
已经返回了视图
。。。这也有点让人困惑。。。为什么mapValues
的行为不同?