2015-04-30 33 views
0

现在我有类似下面的一些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

你可以看看尾递归 – cchantep

回答

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))) 
} 
+0

谢谢。这是懒惰/短路? –

+0

@ZizhengTai:你为什么认为需要懒惰/短路?只要序列中的第一个元素满足条件,'exists'就会返回。 – tuxdna

+0

这里的好处是你可以将它压缩到一行中(0到x)。存在(i =>(i + 1,直到x).exists(j => fn(i,j)))' – tuxdna

2

因为所有你检查的存在,你可以组成2种的用途exists

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

更一般地,如果您关心的不仅仅是确定一个特定的元素存在更多,您可以将您的理解转化为一系列StreamsIterators,或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) 
} 

您还可以使用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

Scala集合默认情况下,严格在其所有的变压器,除了Stream,它懒洋洋地实现其所有变压器的方法。但是,有一种系统的方法可以将每个收藏集变成懒惰的收藏集,反之亦然,这是基于收集的意见。视图是一种特殊的集合,它代表了一些基本集合,但是却懒散地实现了所有变形。

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

+1

使用流只是为了整数循环会矫枉过正?我有点担心这会导致太多的开销...... –

+0

@ZizhengTai我已经添加了一个说明解决开销和其他一些细节。 –