早期从Scala中的for循环返回

时间:2015-04-30 00:39:19

标签: scala functional-programming

现在我有一些类似于以下内容的Scala代码:

def foo(x: Int, fn: (Int, Int) => Boolean): Boolean = {
  for {
    i <- 0 until x
    j <- i + 1 until x
    if fn(i, j)
  } return true
  false
}

但我觉得return true不是那么有用(或者可能是这样?)。有没有办法以更优雅的方式重写这段代码?

一般来说,编写返回早期循环类代码的功能(如果有的话)是什么?

2 个答案:

答案 0 :(得分:4)

有几种方法可以提供帮助,例如findexists等。对于您的情况,请尝试以下方法:

def foo2(x: Int, fn: (Int, Int) => Boolean): Boolean = {
  (0 until x).exists(i => 
     (i+1 until x).exists(j=>fn(i, j)))
}

答案 1 :(得分:2)

由于你要检查的只是存在,你可以只编写exists的2次使用:

(0 until x).exists(i => (i + 1 until x).exists(fn(i, _)))

更一般地说,如果您不仅仅关心某个元素是否存在,那么您可以将您的理解转换为一系列StreamsIteratorsviews,可以使用exists,它将懒惰地评估,避免不必要的循环执行:

def foo(x: Int, fn: (Int, Int) => Boolean): Boolean = {
  (for {
    i <- (0 until x).iterator
    j <- (i + 1 until x).iterator
  } yield(i, j)).exists(fn.tupled)
}

您还可以使用mapflatMap代替fortoStreamview代替iterator

(0 until x).view.flatMap(i => (i + 1 until x).toStream.map(j => i -> j)).exists(fn.tupled)

您还可以在任何集合上使用view来获取一个集合,其中所有变换器都是懒惰地执行的。这可能是使集合遍历短路的最惯用的方法。来自the docs on views

  

除了Stream之外,Scala集合默认在所有变换器中都是严格的,它们懒洋洋地实现了所有变换器方法。但是,有一种系统的方法可以将每个集合转换为惰性集合,反之亦然,它基于集合视图。视图是一种特殊的集合,代表一些基本集合,但是懒惰地实现所有变换器。

就开销而言,它实际上取决于细节!不同的集合具有viewtoStreamiterator的不同实现,其可能在开销量方面有所不同。如果计算fn非常昂贵,那么这个开销可能是值得的,并且为代码保持一致的,惯用的功能样式使其更易于维护,可调试和可读。如果您处于需要进行极端优化的情况,您可能希望回归到return这样的较低级别的构造(没有它自己的开销!)。