¿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:
De los documentos de Scala :
Por
filterlo tanto , tomará la colección original y producirá una nueva colección, perowithFilterno estrictamente (es decir, perezosamente) pasará valores sin filtrar a llamadas posterioresmap/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 (comoforall/exists) para esto, por lo que no se han agregado alFilterMonadictipo de retorno dewithFilter.fuente
viewsi desea que los mapas / filtros sean perezosos.viewywithFilter? ¿Por qué no se usa la vistafor-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 ejemploseq.view filter pvsseq withFilter p.Además de la excelente respuesta de Shadowlands , me gustaría traer un ejemplo intuitivo de la diferencia entre
filterywithFilter.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 aList(1). Este es el caso desde Scala 2.8, porque la para-comprensión se traduce enval 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 deresultsería bastante diferente:List(1, 2, 3). El hecho de que estemos creando lagobanderafalseno tiene ningún efecto en el filtro, porque el filtro ya está hecho. Nuevamente, en Scala 2.8, este problema se resuelve usandowithFilter. CuandowithFilterse usa, la condición se evalúa cada vez que se accede a un elemento dentro de unmapmé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
fuente
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)
fuente
Para la parte forall / existe:
sería lo mismo que (aunque un poco poco intuitivo)
Del mismo modo, .filter (). Existing () se puede combinar en una existe () check?
fuente
Usar para rendimiento puede ser una solución alternativa, por ejemplo:
for { e <- col; if e isNotEmpty } yield e.get(0)fuente
Como solución alternativa, puede implementar otras funciones solo con
mapyflatMap.Además, esta optimización es inútil en colecciones pequeñas ...
fuente