2015-04-30 31 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我已經添加了一個說明解決開銷和其他一些細節。 –