2011-09-28 24 views
17

Bazı işlemlerin A örneğine uygulanabilir olup olmadığını denetleyen bir işlev var mı, varsa, B veya Hiçbiri örneğini döndürür:Scala: Seçeneklerin bir koleksiyonunu filtrelemek

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

Şimdi tüm geçerli olan yeni bir koleksiyon oluşturmak istiyorum B değerlerini geçersiz kılar. Aşağıdaki kod işi yapıyor gibi görünüyor, ama kesinlikle daha iyi bir yol var:

 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] 

Teşekkürler!

+28

flatBu tabloyu aç –

+0

@oxbow_lakes Doğru alıntı olduğuna inanıyorum: _ "Bu nedir? Amatör saat? FlatMap bu bok!" _ –

+0

Bu alıntı, twitter kaynaklı mıydı? – huynhjl

cevap

25

Bu yapmalıyım:

val bs = as.flatMap(checker) 
+0

Çeşitli nedenlerle benim için çalışmıyor: 1. çıkarım yazın, 2. Liste # flatMap bir GenTraversableOnce bekler. Doğru as.flatMap {a => denetleyici [A, B] (a)} – IttayD

+0

"Int" ile "Option [String]' arasında bir işlevle test ettim. En kötü durum, bazı açık türler eklemelisiniz. –

+2

benim için 2.9.1 –

10

yukarıdaki cevabın doğru, ancak checker yeniden yazabilirsiniz eğer, sana PartialFunction ve collect kullanmanızı öneririz. PartialFunction A türü bir fonksiyonudur => Burada A'nın tüm değerleri için tanımlanan gerekli değildir B örnek:

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

collect bağımsız değişken olarak PartialFunction bir örneğini alır ve tüm unsurları uygular Toplamak. Bizim durumumuzda, işlev yalnızca Ints için tanımlanmıştır ve "5" filtrelenmiştir. Yani, collect, map ve filter'un birleşimidir;

+1

'toplamasında 'gerçekten' 'filtre' ve sonra' map' birleşimidir, ancak genellikle diğer yönde çalışmıyor (' map' ** sonra ** 'filter') Çünkü filtreyi case ifadesinin muhafızında tanımlamanız gerekiyor. Bu yüzden OP'nin son iki ifadesini değiştirmek harika olurdu ('.collect {case Some (x) => x}' ile), ancak eğer 'checker' bir geri dönüp dönmeyeceğine karar vermek için herhangi bir önemsiz olmayan hesaplamayı içeriyorsa “Bazıları” veya “Hiçbiri”, bu kısmi bir işlev olarak yazmak zor olabilir. –