2011-09-28 140 views
17

說我有,檢查某些操作是否適用於實例的功能,如果有的話,返回B或無的一個實例:斯卡拉:過濾選項的集合

def checker[A,B](a: A) : Option[B] = ... 

現在我想以形成包含B的所有有效實例的新集合,並刪除None值。下面的代碼似乎是做這項工作,但肯定有更好的辦法:

val as = List[A](a1, a2, a3, ...) 
    val bs = 
    as 
    .map((a) => checker(a)) // List[A] => List[Option[B]] 
    .filter(_.isDefined)  // List[Option[B]] => List[Option[B]] 
    .map(_.get)    // List[Option[B]] => List[B] 

謝謝!

+28

flatMap that shit –

+0

@oxbow_lakes我相信正確的引用是:_「這是什麼?業餘時間?flatMap那狗屎!」_ –

+0

這個引號是否起源於twitter? – huynhjl

回答

25

這應做到:

val bs = as.flatMap(checker) 
+0

由於各種原因,不適用於我:1. type inference,2.列表#flatMap需要一個GenTraversableOnce。正確的是as.flatMap {a => checker [A,B](a)} – IttayD

+0

我用'Int'到'Option [String]'的函數測試了它。最壞的情況下,你必須添加一些明確的類型。 –

+2

適用於2.9.1 –

10

上面的答案是正確的,但如果你可以重寫checker,我建議你使用PartialFunctioncollect。 PartialFunction是類型A的函數=> B中是沒有必要的。此處的所有值定義爲一個簡單的例子:

scala> List(1, 2, 3, 4, "5") collect {case x : Int => x + 42} 
res1: List[Int] = List(43, 44, 45, 46) 

collect需要PartialFunction的實例作爲自變量,並將其應用於的所有元素採集。在我們的情況下,該功能僅被定義爲Ints,並且"5"被過濾。因此,collectmapfilter的組合,這正是您的情況。

+1

'collect'確實是'filter'和map'的組合,但它通常不會在另一個方向工作('map' **然後**'filter') ,因爲您需要在case語句的guard中定義過濾器。所以,用'.collect {case Some(x)=> x}'來代替OP的最後兩條語句會很好,但是如果'checker'涉及到任何一種非平凡的計算來決定是否返回一個「一些」或「無」,這可能很難作爲部分函數來編寫。 –