2012-02-07 26 views
5

Supongamos que tengo un Option[A => Boolean], un List[A], y algún conjunto de operaciones que deseo realizar en un subconjunto de esa lista. Si la opción está configurada, entonces quiero filtrar la lista primero y luego aplicar mis operaciones. Si no, entonces quiero aplicarlo en la lista completa. Un ejemplo:Filtrar condicionalmente una secuencia

val a : Option[Int => Boolean] = Option((a : Int) => a % 2 == 0) 
val b = 1 to 100 

que fácilmente puede hacer lo siguiente:

val c = if (a.isDefined) b.filter(a.get) else b 

Sin embargo, esto implica llamar a.get; ¡Muchos condicionamientos me dejan incapaz de hacer esto! alternativamente, que podía hacer:

val c = b.filter(a.getOrElse(_ => true)) 

Esto se siente mejor, pero ahora estoy atascado con un segundo (aunque trivial) operación que se lleva a cabo para cada elemento de mi secuencia. Espero que se optimice, pero esto todavía se siente imperfecto.

Lo que me gustaría es algo que no tenga ninguno de los defectos. Parece que debería haber una buena manera de hacerlo, ¿alguna idea?

Respuesta

10

Sólo tiene que utilizar los métodos normales de manipulación opción:

a.map(b.filter).getOrElse(b) 
+0

Sí; por alguna razón, no veía la idea de cambiar la situación. Esto es muy ordenado. – Submonoid

+0

Sin embargo, una razón más por la que el patrón "option.map(). GetOrElse()" debe agregarse a la biblioteca estándar. Siempre es una de las primeras cosas que propongo. –

+2

@DaveGriffith - De hecho. Lo tengo también, llamado 'fold' (como Scalaz), con la sintaxis' o.map (f) .getOrElse (b) 'convirtiéndose en' o.fold (b) (f) '. –

1

¿Qué tal el cambio de una a:

val a : Option[Seq[Int] => Seq[Int]] = Option((a : Seq[Int]) => a.filter(_ % 2 == 0)) 
val b = 1 to 100 
val c = a.getOrElse((f:Seq[Int]) => f)(b) 

(Tenga en cuenta que no he probado lo anterior, sino que debe darle la idea)

+0

¡Ah, esto se ve bien! La idea de cambiar la situación para aplicar la lista a la opción en lugar de la opción a la lista hace que la situación sea mucho más agradable. Sabía que me estaba perdiendo algo. – Submonoid

3

Básicamente igual que la solución de Rex Kerr, pero utiliza fold de Scalaz para que sea un poco más concisa.

En general, x.fold(f, g)x.map(f).getOrElse(g).

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> a.fold(b.filter, b) 
res112: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100) 
1

Personalmente prefiero la claridad de coincidencia de patrones; es una traducción muy directa de su descripción en prosa al código:

val c = a match { 
    case Some(f) => b.filter(f) 
    case None => b 
} 
Cuestiones relacionadas