2015-04-03 14 views
10

c'è qualcosa in Scala comecondizione nella mappa delle funzioni

condition ? first_expression : second_expression; 

che posso usare all'interno della funzione mappa in scala? Voglio essere in grado di scrivere qualcosa del genere:

val statuses = tweets.map(status => status.isTruncate? //do nothing | status.getText()) 

se la funzione inline non è possibile, come posso scrivere un condizione all'interno mappa?

risposta

2

è possibile filtrare e quindi mappare come,

val statuses = tweets.filter(_.isTruncate).map(status=> status.getText()) 
+2

Questo è _not_ il modo migliore per avvicinarsi a risolvere il problema. Fa sì che gli oggetti filtrati vengano attraversati due volte; tutti gli elementi per il filtro passano e quindi gli articoli filtrati con successo una seconda volta. Dato un ampio elenco e una percentuale sostanziale che viene mantenuta con il filtro, la soluzione è anche abbastanza inefficiente. A proposito, l'ultima riga di risposta di Ben utilizza una vista che può spostare la tua soluzione a diventare efficiente. – chaotic3quilibrium

19

L'operatore ?, a volte chiamato il ternario operatore non è necessaria in Scala, dal momento che è sussunto da un regolare if-else espressione:

val x = if (condition) 1 else 2 

Per utilizzare questo in un map, è possibile utilizzare flatMap e quindi restituire un Option su entrambi i lati dello if-else. Dal momento che Option è implicitamente convertibile in Iterable, l'effetto è che la lista è appiattita, e il Nones vengono filtrati:

val statuses = tweets.flatMap(status => if (status.isTruncate) None else Some(status.getText)) 

Ciò equivale a utilizzare map e poi flatten:

val statuses = tweets.map(status => if (status.isTruncate) None else Some(status.getText)).flatten 

Più idiomaticamente, è possibile utilizzare collect, che consente di utilizzare filter e map in un'unica operazione utilizzando una funzione parziale:

val statuses = tweets.collect { 
    case status if !status.isTruncate => status.getText 
} 

si può anche fare questo in 2 passaggi utilizzando filter e map:

Il rovescio della medaglia è che questo sarà iterare oltre l'elenco due volte, che può essere indesiderabile. Se si utilizza view, è possibile utilizzare questa stessa logica, e solo iterazioni su lista una volta:

val statuses = tweets.view.filterNot(_.isTruncate).map(_.getText) 
+1

Poiché la domanda è codificata [tag: apache-spark], 'tweets' è probabilmente un RDD. In tal caso non esiste il metodo 'filterNot' e non' views'. Tuttavia, gli RDD sono pigri per natura, quindi non c'è nemmeno bisogno di 'views'. –