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?

Author: sideshowbarker, 2011-10-14

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.

 261
Author: agilesteel,
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)(_)
 170
Author: Kim Stebel,
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.

 42
Author: thoredge,
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)
}
 5
Author: Martin Smith,
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.

 4
Author: Alexey Romanov,
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 acumulador z, como parámetro adicional, que se devuelve cuando se llama a foldLeft 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).

 2
Author: C8H10N4O2,
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) (_)

 0
Author: Henry H.,
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