现在我有一些类似于以下内容的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
不是那么有用(或者可能是这样?)。有没有办法以更优雅的方式重写这段代码?
一般来说,编写返回早期循环类代码的功能(如果有的话)是什么?
答案 0 :(得分:4)
有几种方法可以提供帮助,例如find
,exists
等。对于您的情况,请尝试以下方法:
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, _)))
更一般地说,如果您不仅仅关心某个元素是否存在,那么您可以将您的理解转换为一系列Streams
,Iterators
或views
,可以使用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)
}
您还可以使用map
和flatMap
代替for
,toStream
或view
代替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集合默认在所有变换器中都是严格的,它们懒洋洋地实现了所有变换器方法。但是,有一种系统的方法可以将每个集合转换为惰性集合,反之亦然,它基于集合视图。视图是一种特殊的集合,代表一些基本集合,但是懒惰地实现所有变换器。
就开销而言,它实际上取决于细节!不同的集合具有view
,toStream
和iterator
的不同实现,其可能在开销量方面有所不同。如果计算fn
非常昂贵,那么这个开销可能是值得的,并且为代码保持一致的,惯用的功能样式使其更易于维护,可调试和可读。如果您处于需要进行极端优化的情况,您可能希望回归到return
这样的较低级别的构造(没有它自己的开销!)。