2012-01-20 13 views
6

¿Es posible expresar el siguiente código de forma que el mapa y la omisión nula se expresen en una sola llamada?Combinación de nulos de mapa y filtro en Scala

list.map(_.accept(this, arg).asInstanceOf[T]).filter(_ != null) 
+0

supongo que '_.accept (esto, arg) 'puede devolver' null'. En este caso, un poco más idiomático (aunque todavía con dos llamadas): 'list.map (i => Opción (i.accept (this, arg) .asInstanceOf [T])). Aplastar' –

+1

Por favor, alguien me corrija si ' estoy equivocado, pero ¿no es 'recoger' la combinación de' map' y 'filter'? ¿O era al revés? ¿O simplemente estoy equivocado? ;) – agilesteel

+1

@agilesteel, sí, collect podría funcionar. ¿Podría contribuir con un fragmento de código? –

Respuesta

11
list flatMap { i => Option(i.accept(this, arg).asInstanceOf[T]) } 

o, alternativamente, si se quiere, (aunque esto será convertido más o menos en su expresión original)

for { 
    item <- list 
    itemConverted = item.accept(this, arg).asInstanceOf[T] 
    itemNonNull = itemConverted if itemConverted != 0 
} yield itemNonNull 

usando collect sería posible pero probablemente llamarían accept dos veces en la mayoría de los argumentos debido a la prueba isDefinedAt de la función parcial:

list collect { 
    case i if i.accept(this, arg).asInstanceOf[T] != null => i.accept(this, arg).asInstanceOf[T] 
} 

Uno necesitaría usar algunas memorias (o extractores inteligentes) para evitar esto.

+0

gracias por la respuesta! –

6

Si usted está preocupado por el rendimiento, puede agregar .view

list.view.map(_.accept(this, arg).asInstanceOf[T]).filter(_ != null) 

view hace que el recorrido para convertirse en vago, por lo tanto el map y filter se llevará a cabo en un solo pase la lista en lugar de dos pasos separados.

Si usted está preocupado por la reutilización de este patrón, se puede definir su propia función auxiliar:

def mapNN[A,B](list: List[A])(f: A => B) = { 
    list.view.map(f(_)).filter(_ != null) 
} 

mapNN(list)(_.accept(this, arg).asInstanceOf[T]) 

Probando ...

> mapNN(List(1,2,3))(x => if (x%2==0) x else null).toList 
res7: List[Any] = List(2) 
+0

¿Puedes explicarme más sobre esta parte, así que el mapa y el filtro se realizarán en una pasada sobre la lista en lugar de en dos pases separados? ¿Cómo solo puede necesitar un pase para aplicar 2 transformaciones? –

+1

@MinhThai Aquí hay una explicación decente de 'view': https://stackoverflow.com/a/6799739/208257 Básicamente, hace que las transformaciones sean flojas. Retrasa incluso haciendo una sola pasada, hasta que llamas a 'toList', momento en el que hace una sola pasada, aplicando cada transformación de forma gradual a medida que avanza. –