¿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 pyc withFilter pes que el primero crea una nueva colección, mientras que el segundo sólo se restringe el dominio del subsiguientesmap,flatMap,foreach, ywithFilteroperaciones.
Por filterlo tanto , tomará la colección original y producirá una nueva colección, pero withFilterno 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, withFilterestá 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 FilterMonadictipo de retorno de withFilter.
viewsi desea que los mapas / filtros sean perezosos.
viewy withFilter? ¿Por qué no se usa la vista for-loops?
Don’t create temporary collectionsen 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 pvs seq withFilter p.
Además de la excelente respuesta de Shadowlands , me gustaría traer un ejemplo intuitivo de la diferencia entre filtery 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 resultser 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 resultsería bastante diferente: List(1, 2, 3). El hecho de que estemos creando la gobandera falseno 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 withFilterse usa, la condición se evalúa cada vez que se accede a un elemento dentro de un mapmé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 mapy flatMap.
Además, esta optimización es inútil en colecciones pequeñas ...