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
的行为不同?