Scala数据结构:操作链(如mapValues,filter ...)和中间结果

时间:2013-01-08 17:11:04

标签: 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
}

结果是

rest : scala.collection.immutable.Map[String,Int] = Map(apple -> 4, banana -> 2, kiwi -> 1)

虽然我不是Scala的专家,但我知道该语言不是懒惰的(与Haskell不同),因此mapValues将产生一个中间Map,而后者将作为输入到filterNot(如果链中还有其他操作,那么。)

如何避免这种无用的中间数据结构?

注意:我知道这个问题可以推广到其他数据结构。这里我使用Map只是因为它是我在实际代码中使用的数据结构(尽管有其他数据:))

3 个答案:

答案 0 :(得分:7)

您可以使用任何集合类的view方法创建一个集合视图,该视图将懒惰地应用mapfilter等方法。见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}