2011-09-28 38 views
17

Decir que tengo una función que comprueba si alguna operación es aplicable a una instancia de A y, si es así, devuelve una instancia de B o Nada:Scala: filtrar una colección de opciones

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

Ahora quiero para formar una nueva colección que contenga todas las instancias válidas de B, descartando los valores Ninguno. El siguiente código parece hacer el trabajo, pero sin duda hay una mejor manera:

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] 

Gracias!

+28

flatMap that shit –

+0

@oxbow_lakes Creo que la cita correcta es: _ "¿Qué es esto? Hora de aficionados? FlatMap that shit!" _ –

+0

¿Esa cita se originó en twitter? – huynhjl

Respuesta

25

Esto debe hacerlo:

val bs = as.flatMap(checker) 
+0

No funciona para mí por varias razones: 1. escriba inference, 2. List # flatMap espera un GenTraversableOnce. Lo correcto es as.flatMap {a => checker [A, B] (a)} – IttayD

+0

Lo probé con una función de 'Int' a' Option [String] '. En el peor de los casos, debe agregarle algunos tipos explícitos. –

+2

funciona para mí en 2.9.1 –

10

La respuesta anterior es correcta, pero si se puede reescribir checker, le sugiero que utilice PartialFunction y collect. Función parcial es una función del tipo A => B que no es necesario definir para todos los valores de A. Aquí está un ejemplo simple:

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

collect toma una instancia de función parcial como argumento y lo aplica a todos los elementos de la colección. En nuestro caso, la función se define solo para Ints y "5" se filtra. Por lo tanto, collect es una combinación de map y filter, que es exactamente tu caso.

+1

'collect' es de hecho una combinación de' filter' y luego 'map', pero generalmente no funciona en la otra dirección (' map' ** then ** 'filter') , ya que necesita definir el filtro en el protector de la declaración de caso. Así que sería genial para reemplazar las últimas dos declaraciones del OP (con '.collect {case Some (x) => x}'), pero si 'checker' implica algún tipo de cálculo no trivial para decidir si se devuelve un 'Some' o' None', esto podría ser difícil de escribir como una función parcial. –

Cuestiones relacionadas