diferencia entre foldLeft y reduceLeft en Scala
He aprendido la diferencia básica entre foldLeft
y reduceLeft
FoldLeft:
- se debe pasar el valor inicial
ReduceLeft:
- toma el primer elemento de la colección como valor inicial
- lanza excepción si la colección está vacía
¿hay alguna otra diferencia ?
¿Alguna razón específica para tener dos métodos con funcionalidad similar?
7 answers
Pocas cosas que mencionar aquí, antes de dar la respuesta real:{[24]]}
- Su pregunta no tiene nada que ver con
left
, se trata más bien de la diferencia entre reducir y plegar - La diferencia no es la implementación en absoluto, basta con mirar las firmas.
- La pregunta no tiene nada que ver con Scala en particular, se trata más bien de los dos conceptos de programación funcional.
Volver a su pregunta:
Aquí está la firma de foldLeft
(también podría haber sido foldRight
para el punto que voy a hacer):
def foldLeft [B] (z: B)(f: (B, A) => B): B
Y aquí está la firma de reduceLeft
(de nuevo la dirección no importa aquí)
def reduceLeft [B >: A] (f: (B, A) => B): B
Estos dos se ven muy similares y por lo tanto causaron la confusión. reduceLeft
es un caso especial de foldLeft
(que por cierto significa que a veces puede expresar lo mismo usando cualquiera de ellos).
Cuando llame a reduceLeft
decir en un List[Int]
se literalmente reducir toda la lista de enteros en un solo valor, que va a ser de tipo Int
(o un supertipo de Int
, por lo tanto [B >: A]
).
Cuando llamas a foldLeft
say on a List[Int]
doblará toda la lista (imagina enrollar un pedazo de papel) en un solo valor, pero este valor no tiene que estar ni siquiera relacionado con Int
(por lo tanto [B]
).
Aquí hay un ejemplo:
def listWithSum(numbers: List[Int]) = numbers.foldLeft((List[Int](), 0)) {
(resultingTuple, currentInteger) =>
(currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}
Este método toma un List[Int]
y devuelve un Tuple2[List[Int], Int]
o (List[Int] -> Int)
. Calcula la suma y devuelve un tupla con una lista de enteros y su suma. Por cierto, la lista se devuelve al revés, porque usamos foldLeft
en lugar de foldRight
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-23 15:48:19
reduceLeft
es solo un método de conveniencia. Es equivalente a
list.tail.foldLeft(list.head)(_)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-15 08:15:27
foldLeft
es más genérico, puedes usarlo para producir algo completamente diferente a lo que originalmente pusiste. Mientras que reduceLeft
solo puede producir un resultado final del mismo tipo o super tipo del tipo de colección. Por ejemplo:
List(1,3,5).foldLeft(0) { _ + _ }
List(1,3,5).foldLeft(List[String]()) { (a, b) => b.toString :: a }
El foldLeft
aplicará el cierre con el último resultado plegado (la primera vez usando el valor inicial) y el siguiente valor.
reduceLeft
por otro lado, primero combinará dos valores de la lista y los aplicará al cierre. A continuación se combinará el resto de los valores con el resultado acumulativo. Véase:
List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }
Si la lista está vacía foldLeft
puede presentar el valor inicial como un resultado legal. reduceLeft
por otro lado no tiene un valor legal si no puede encontrar al menos un valor en la lista.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-13 09:29:42
Como referencia, reduceLeft
se producirá un error si se aplica a un contenedor vacío con el siguiente error.
java.lang.UnsupportedOperationException: empty.reduceLeft
Reelaborar el código para usar
myList foldLeft(List[String]()) {(a,b) => a+b}
Es una opción potencial. Otra es usar la variante reduceLeftOption
que devuelve un resultado envuelto en una opción.
myList reduceLeftOption {(a,b) => a+b} match {
case None => // handle no result as necessary
case Some(v) => println(v)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-26 16:29:17
La razón básica por la que ambos están en la biblioteca estándar de Scala es probablemente porque ambos están en la biblioteca estándar de Haskell (llamada foldl
y foldl1
). Si reduceLeft
no lo fuera, a menudo se definiría como un método de conveniencia en diferentes proyectos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-14 08:23:56
De Principios de Programación Funcional en Scala (Martin Odersky):
La función
reduceLeft
se define en términos de una función más general,foldLeft
.
foldLeft
es como {[1] } pero toma un acumuladorz
, como parámetro adicional, que se devuelve cuando se llama afoldLeft
en una lista vacía:
(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x
[a diferencia de reduceLeft
, que lanza una excepción cuando se llama en una lista vacía.]
El curso (ver conferencia 5.5) proporciona definiciones abstractas de estas funciones, lo que ilustra sus diferencias, aunque son muy similares en su uso de coincidencia de patrones y recursión.
abstract class List[T] { ...
def reduceLeft(op: (T,T)=>T) : T = this match{
case Nil => throw new Error("Nil.reduceLeft")
case x :: xs => (xs foldLeft x)(op)
}
def foldLeft[U](z: U)(op: (U,T)=>U): U = this match{
case Nil => z
case x :: xs => (xs foldLeft op(z, x))(op)
}
}
Tenga en cuenta que foldLeft
devuelve un valor de tipo U
, que no es necesariamente el mismo tipo que List[T]
, pero reduceLeft devuelve un valor del mismo tipo que la lista).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-01 22:11:19
Para entender realmente qué estás haciendo con fold / reduce, compruebe esto: http://wiki.tcl.tk/17983 muy buena explicación. una vez que obtengas el concepto de plegado, reducir vendrá junto con la respuesta anterior: lista.cola.foldLeft (list.head) (_)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-06 10:21:39