如何在scala中削减for-comprehension short(突破它)?

时间:2012-11-28 01:38:20

标签: scala break for-comprehension infinite-sequence

我有一段代码,代码如下:

val e2 = for (e <- elements if condition(expensiveFunction(e))) yield {
            expensiveFunction(e)
         }

如果某些元素的条件为真,那么对于所有剩余的元素则为假。

不幸的是,这不起作用(即使我忽略了性能),因为我的elements是一个无限的迭代器。

有没有办法在for-comprehension中使用“break”,所以当某个条件成立时它会停止产生元素?否则,计算我的e2

的scala-idiomatic方法是什么?

5 个答案:

答案 0 :(得分:20)

你可以采用惰性方法:

val e2 = elements.toIterator                    
          .map(expensiveFunction)
          .takeWhile(result => result == true) // or just .takeWhile(identity)
// you may want to strict iterator, (e.g. by calling .toList) at the end

所以你按需计算昂贵的功能,如果某些步骤有假,你就不会做不必要的工作。

答案 1 :(得分:8)

scala> def compute(i: Int) = { println(s"f$i"); 10*i }
compute: (i: Int)Int

scala> for (x <- Stream range (0, 20)) yield compute(x)
f0
res0: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res0 takeWhile (_ < 100)
res1: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res1.toList
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
res2: List[Int] = List(0, 10, 20, 30, 40, 50, 60, 70, 80, 90)

编辑,另一个演示:

scala> def compute(i: Int) = { println(s"f$i"); 10*i }
compute: (i: Int)Int

scala> for (x <- Stream range (0, 20)) yield compute(x)
f0
res0: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res0 takeWhile (_ < 100)
res1: scala.collection.immutable.Stream[Int] = Stream(0, ?)

scala> res1.toList
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
res2: List[Int] = List(0, 10, 20, 30, 40, 50, 60, 70, 80, 90)

scala> Stream.range(0,20).map(compute).toList
f0
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
f11
f12
f13
f14
f15
f16
f17
f18
f19
res3: List[Int] = List(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190)

scala> Stream.range(0,20).map(compute).takeWhile(_ < 100).toList
f0
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
res4: List[Int] = List(0, 10, 20, 30, 40, 50, 60, 70, 80, 90)

答案 2 :(得分:3)

你可以使用takeWhile:

elements.takeWhile(condition(expensiveFunction(_)))

答案 3 :(得分:0)

找到了这个解决方案:

(for (e <- elements) yield {
  val x= expensiveFunction(e)
  if (condition(x)) Some(x) else None
}).takeWhile(_.nonEmpty).map(_.get)

一个更好的人,有人吗?

答案 4 :(得分:0)

这是我的想法: 如果元素已经是一个惰性容器(如Stream,Iterator):

(for (e <- elements; 
      buf = expensiveFunction(e);  
      if condition(buf)) yield buf).headOption

或不:

(for (e <- elements.view; 
      buf = expensiveFunction(e);  
      if condition(buf)) yield buf).headOption