Scala:对集合应用函数并仅产生一些结果

Pek*_*kka 2 scala

假设我有一个昂贵的功能f 和许多值v

def f(x: Int) = {
  x + 3
}

val v = 0 to 10e7.toInt
Run Code Online (Sandbox Code Playgroud)

现在,我想申请fv,选择基于一定条件下的一些结果.

我可以这样做

v.map(f).filter(_ > 10e7 - 5)
Run Code Online (Sandbox Code Playgroud)

但这根本不可行,因为整体v.map(f)将首先存储在内存中.

那么其他选择是:

for(a <- v if f(a) > 10e7 - 5) yield f(a)
Run Code Online (Sandbox Code Playgroud)

但是现在我需要为某些元素计算两次f,这是不可能的!

那么如何在不存储整个结果的情况下实现过滤,但仍能得到结果.逻辑看起来像这样(显然这不起作用):

for(a <- v) {
  val b = f(a)
  if(b > 10e7 - 5) yield b
}
Run Code Online (Sandbox Code Playgroud)

Łuk*_*asz 5

怎么样iterator

scala> v.iterator.map(f).filter(_ > 10e7 - 5).toVector
res4: Vector[Int] = Vector(99999996, 99999997, 99999998, 99999999, 100000000, 100000001, 100000002, 100000003)
Run Code Online (Sandbox Code Playgroud)

要么 view

scala>  v.view.map(f).filter(_ > 10e7 - 5).toVector
res5: Vector[Int] = Vector(99999996, 99999997, 99999998, 99999999, 100000000, 100000001, 100000002, 100000003)
Run Code Online (Sandbox Code Playgroud)

两者都不会创建任何中间集合.

顺便说一句,不要在理解中寻找一些魔力,它们只是语法糖,你可以用这个做大致相当的事情:

scala> (for {
          a <- v.iterator
          fa = f(a)
          if fa > 10e7 - 5
        } yield fa).toVector
res9: Vector[Int] = Vector(99999996, 99999997, 99999998, 99999999, 100000000, 100000001, 100000002, 100000003)
Run Code Online (Sandbox Code Playgroud)

如果你不能iteratorv映射中获得整个集合仍然会在你的示例中出现OutOfMemoryError.