¿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
filter
lo tanto , tomará la colección original y producirá una nueva colección, perowithFilter
no 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,
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 (comoforall
/exists
) para esto, por lo que no se han agregado alFilterMonadic
tipo de retorno dewithFilter
.fuente
view
si desea que los mapas / filtros sean perezosos.view
ywithFilter
? ¿Por qué no se usa la vistafor-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 ejemploseq.view filter p
vsseq withFilter p
.Además de la excelente respuesta de Shadowlands , me gustaría traer un ejemplo intuitivo de la diferencia entre
filter
ywithFilter
.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 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 deresult
sería bastante diferente:List(1, 2, 3)
. El hecho de que estemos creando lago
banderafalse
no tiene ningún efecto en el filtro, porque el filtro ya está hecho. Nuevamente, en Scala 2.8, este problema se resuelve usandowithFilter
. CuandowithFilter
se usa, la condición se evalúa cada vez que se accede a un elemento dentro de unmap
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
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
map
yflatMap
.Además, esta optimización es inútil en colecciones pequeñas ...
fuente