¿Es siempre más eficaz usar withFilter en lugar de filter, cuando luego se aplican funciones como mapa, mapa plano, etc.?
¿Por qué solo se admiten mapas, mapas planos y foreach? (Funciones esperadas como forall / existe también)
¿Es siempre más eficaz usar withFilter en lugar de filter, cuando luego se aplican funciones como mapa, mapa plano, etc.?
¿Por qué solo se admiten mapas, mapas planos y foreach? (Funciones esperadas como forall / existe también)
Respuestas:
Nota: la diferencia entre
c filter p
yc withFilter p
es que el primero crea una nueva colección, mientras que el segundo sólo se restringe el dominio del subsiguientesmap
,flatMap
,foreach
, ywithFilter
operaciones.
Por filter
lo tanto , tomará la colección original y producirá una nueva colección, pero withFilter
no estrictamente (es decir, perezosamente) pasará valores sin filtrar a llamadas posteriores map
/ flatMap
/ withFilter
, guardando una segunda pasada a través de la colección (filtrada). Por lo tanto, será más eficiente al pasar a estas llamadas de método posteriores.
De hecho, withFilter
está diseñado específicamente para trabajar con cadenas de estos métodos, que es en lo que se quita el azúcar para la comprensión. No se requieren otros métodos (como forall
/ exists
) para esto, por lo que no se han agregado al FilterMonadic
tipo de retorno de withFilter
.
view
si desea que los mapas / filtros sean perezosos.
view
y withFilter
? ¿Por qué no se usa la vista for-loops
?
Don’t create temporary collections
en la sección vinculada.
withFilter
, el propio Martin Odersky lo usa explícitamente en sus cursos Scala en Coursera, que recomiendo encarecidamente. Dado que lo hace, puede que los demás también se sientan cómodos al hacerlo, aunque la diferencia suele ser de solo un carácter. Por ejemplo seq.view filter p
vs seq withFilter p
.
Además de la excelente respuesta de Shadowlands , me gustaría traer un ejemplo intuitivo de la diferencia entre filter
y withFilter
.
Consideremos el siguiente código
val list = List(1, 2, 3)
var go = true
val result = for(i <- list; if(go)) yield {
go = false
i
}
La mayoría de la gente espera result
ser igual a List(1)
. Este es el caso desde Scala 2.8, porque la para-comprensión se traduce en
val result = list withFilter {
case i => go
} map {
case i => {
go = false
i
}
}
Como puede ver, la traducción convierte la condición en una llamada a withFilter
. Antes de Scala 2.8, para la comprensión se tradujeron a algo como lo siguiente:
val r2 = list filter {
case i => go
} map {
case i => {
go = false
i
}
}
El uso filter
, el valor de result
sería bastante diferente: List(1, 2, 3)
. El hecho de que estemos creando la go
bandera false
no tiene ningún efecto en el filtro, porque el filtro ya está hecho. Nuevamente, en Scala 2.8, este problema se resuelve usando withFilter
. Cuando withFilter
se usa, la condición se evalúa cada vez que se accede a un elemento dentro de un map
método.
Referencia : - p.120, Scala en acción (cubre Scala 2.10), Publicaciones Manning, Milanjan Raychaudhuri - Pensamientos de Odersky sobre la traducción para la comprensión
La razón principal por la que forall / exist no está implementado es que el caso de uso es que:
Para implementar forall / exist necesitamos obtener todos los elementos, perdiendo la pereza.
Así por ejemplo:
import scala.collection.AbstractIterator
class RandomIntIterator extends AbstractIterator[Int] {
val rand = new java.util.Random
def next: Int = rand.nextInt()
def hasNext: Boolean = true
}
//rand_integers is an infinite random integers iterator
val rand_integers = new RandomIntIterator
val rand_naturals =
rand_integers.withFilter(_ > 0)
val rand_even_naturals =
rand_naturals.withFilter(_ % 2 == 0)
println(rand_even_naturals.map(identity).take(10).toList)
//calling a second time we get
//another ten-tuple of random even naturals
println(rand_even_naturals.map(identity).take(10).toList)
Tenga en cuenta que ten_rand_even_naturals sigue siendo un iterador. Solo cuando llamemos a toList, los números aleatorios se generarán y filtrarán en cadena
Tenga en cuenta que map (identidad) es equivalente a map (i => i) y se usa aquí para convertir un objeto withFilter de nuevo al tipo original (por ejemplo, una colección, una secuencia, un iterador)
Usar para rendimiento puede ser una solución alternativa, por ejemplo:
for {
e <- col;
if e isNotEmpty
} yield e.get(0)
Como solución alternativa, puede implementar otras funciones solo con map
y flatMap
.
Además, esta optimización es inútil en colecciones pequeñas ...