2011-09-28 11 views
17

Dire Ho una funzione che controlla se qualche operazione sia applicabile a un'istanza di A e, in caso affermativo, restituisce un'istanza di B o Nessuno:Scala: filtrare un insieme di opzioni

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

Ora voglio per formare una nuova raccolta che contenga tutte le istanze valide di B, lasciando cadere i valori Nessuno. Il seguente codice sembra fare il lavoro, ma c'è sicuramente un modo migliore:

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] 

Grazie!

+28

flatMap che merda –

+0

@oxbow_lakes Credo che la citazione corretta sia: _ "Cos'è questa? Ora amatoriale? FlatMap quella merda!" _ –

+0

La citazione è nata su twitter? – huynhjl

risposta

25

Questo dovrebbe farlo:

val bs = as.flatMap(checker) 
+0

Non funziona per me per vari motivi: 1. digitare inferenza, 2. Lista # flatMap prevede un GenTraversableOnce. Il corretto è as.flatMap {a => checker [A, B] (a)} – IttayD

+0

L'ho provato con una funzione da 'Int' a' Option [String] '. Nel peggiore dei casi, devi aggiungere alcuni tipi espliciti. –

+2

funziona per me in 2.9.1 –

10

La risposta di cui sopra è corretta, ma se si può riscrivere checker, vi suggerisco di utilizzare PartialFunction e collect. Funzione parziale è funzione del tipo A => B che non è necessario definita per tutti i valori di A. Questo è un semplice esempio:

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

collect prende un'istanza di funzione parziale come argomento e si applica a tutti gli elementi del collezione. Nel nostro caso la funzione è definita solo per Ints e "5" viene filtrata. Quindi, collect è una combinazione di map e filter, che è esattamente il tuo caso.

+1

'collect' è in effetti una combinazione di' filter' e quindi 'map', ma generalmente non funziona nell'altra direzione (' map' ** then ** 'filter') , dal momento che è necessario definire il filtro nella guardia della dichiarazione del caso. Quindi sarebbe grandioso sostituire le ultime due istruzioni dell'OP (con '.collect {case Some (x) => x}'), ma se 'checker' implica qualche tipo di calcolo non banale per decidere se restituire un 'Some' o a' None', potrebbe essere difficile scrivere come una funzione parziale. –

Problemi correlati