¿Hay alguna diferencia entre foreach y el mapa?

Bueno, esto es más una pregunta de ciencias de la computación, que una pregunta basada en un idioma en particular, pero ¿hay alguna diferencia entre una operación de mapa y una de foreach? ¿O simplemente son nombres diferentes para la misma cosa?

Diferente.

foreach itera sobre una lista y aplica alguna operación con efectos secundarios a cada miembro de la lista (como por ejemplo guardar cada uno en la base de datos)

el mapa itera sobre una lista, transforma cada miembro de esa lista y devuelve otra lista del mismo tamaño con los miembros transformados (como convertir una lista de cadenas en mayúsculas)

La diferencia importante entre ellos es que el map acumula todos los resultados en una colección, mientras que foreach no devuelve nada. map se usa generalmente cuando se quiere transformar una colección de elementos con una función, mientras que foreach simplemente ejecuta una acción para cada elemento.

En resumen, foreach es para aplicar una operación en cada elemento de una colección de elementos, mientras que el map es para transformar una colección en otra.

Hay dos diferencias significativas entre foreach y el map .

  1. foreach no tiene restricciones conceptuales sobre la operación que aplica, aparte de tal vez aceptar un elemento como argumento. Es decir, la operación puede no hacer nada, puede tener un efecto secundario, puede devolver un valor o puede no devolver un valor. Todas las preocupaciones de foreach se basan en iterar sobre una colección de elementos y aplicar la operación en cada elemento.

    map , por otro lado, tiene una restricción en la operación: espera que la operación devuelva un elemento, y probablemente también acepte un elemento como argumento. La operación del map itera sobre una colección de elementos, aplicando la operación en cada elemento y finalmente almacenando el resultado de cada invocación de la operación en otra colección. En otras palabras, el map transforma una colección en otra.

  2. foreach funciona con una sola colección de elementos. Esta es la colección de entrada.

    map funciona con dos colecciones de elementos: la colección de entrada y la colección de salida.

No es un error relacionar los dos algoritmos: de hecho, puede ver los dos jerárquicamente, donde el map es una especialización de foreach . Es decir, puede usar foreach y hacer que la operación transforme su argumento e insertarlo en otra colección. Entonces, el algoritmo foreach es una abstracción, una generalización, del algoritmo del map . De hecho, dado que foreach no tiene restricciones en su funcionamiento, podemos decir con seguridad que foreach es el mecanismo de bucle más simple que existe, y que puede hacer cualquier cosa que un bucle pueda hacer. map , así como otros algoritmos más especializados, están ahí para la expresividad: si deseas mapear (o transformar) una colección en otra, tu intención es más clara si usas el map que si usas foreach .

Podemos extender esta discusión más a fondo, y considerar el algoritmo de copy : un bucle que clona una colección. Este algoritmo también es una especialización del algoritmo foreach . Podría definir una operación que, dado un elemento, insertará ese mismo elemento en otra colección. Si utiliza foreach con esa operación, en realidad realizó el algoritmo de copy , aunque con claridad, expresividad o explicitud reducidas. Vamos más allá: podemos decir que el map es una especialización de copy , una especialización de foreach . map puede cambiar cualquiera de los elementos sobre los que itera. Si el map no cambia ninguno de los elementos, entonces simplemente copió los elementos, y el uso de la copia expressá el bash con mayor claridad.

El algoritmo foreach sí mismo puede tener o no un valor de retorno, dependiendo del idioma. En C ++, por ejemplo, foreach devuelve la operación que recibió originalmente. La idea es que la operación tenga un estado, y es posible que desee que la operación vuelva a inspeccionar cómo evolucionó sobre los elementos. map también puede devolver un valor o no. En C ++ transform (el equivalente para el map aquí) pasa a devolver un iterador al final del contenedor de salida (colección). En Ruby, el valor de retorno del map es la secuencia de salida (recostackción). Entonces, el valor de retorno de los algoritmos es realmente un detalle de implementación; su efecto puede o no ser lo que devuelven.

Array.protototype.map método Array.protototype.map y Array.protototype.forEach son bastante similares.

Ejecute el siguiente código: http://labs.codecademy.com/bw1/6#:workspace

 var arr = [1, 2, 3, 4, 5]; arr.map(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); }); console.log(); arr.forEach(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); }); 

Dan el resultado exacto de ídem.

 arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 

Pero el giro viene cuando ejecuta el siguiente código:

Aquí simplemente he asignado el resultado del valor de retorno del mapa y de cada método.

 var arr = [1, 2, 3, 4, 5]; var ar1 = arr.map(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); return val; }); console.log(); console.log(ar1); console.log(); var ar2 = arr.forEach(function(val, ind, arr){ console.log("arr[" + ind + "]: " + Math.pow(val,2)); return val; }); console.log(); console.log(ar2); console.log(); 

¡Ahora el resultado es algo complicado!

 arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 [ 1, 2, 3, 4, 5 ] arr[0]: 1 arr[1]: 4 arr[2]: 9 arr[3]: 16 arr[4]: 25 undefined 

Conclusión

Array.prototype.map devuelve una matriz, pero Array.prototype.forEach no lo hace. Entonces puede manipular la matriz devuelta dentro de la función de callback pasada al método de mapa y luego devolverla.

Array.prototype.forEach solo recorre la matriz dada para que pueda hacer sus cosas mientras recorre la matriz.

la diferencia más ‘visible’ es que el mapa acumula el resultado en una nueva colección, mientras que foreach se hace solo para la ejecución misma.

pero hay un par de supuestos adicionales: dado que el ‘propósito’ del mapa es la nueva lista de valores, realmente no importa el orden de ejecución. de hecho, algunos entornos de ejecución generan código paralelo, o incluso introducen algunas memorias para evitar llamar a valores repetidos, o pereza, para evitar llamar a alguno.

foreach, por otro lado, se llama específicamente para los efectos secundarios; por lo tanto, el orden es importante, y por lo general no se puede paralelizar.

Respuesta corta: map y forEach son diferentes. Además, de manera informal, el map es un superconjunto estricto de forEach .

Respuesta larga: Primero, forEach una línea de descripciones para cada forEach y map :

  • forEach itera sobre todos los elementos, llamando a la función suministrada en cada uno.
  • map itera sobre todos los elementos, llama a la función suministrada en cada uno y produce una matriz transformada al recordar el resultado de cada llamada a la función.

En muchos idiomas, forEach a each se le llama simplemente each . La siguiente discusión usa JavaScript solo como referencia. Realmente podría ser cualquier otro idioma.

Ahora, usemos cada una de estas funciones.

Usando forEach :

Tarea 1: escriba una función printSquares , que acepta una matriz de números arr e imprime el cuadrado de cada elemento en ella.

Solución 1:

 var printSquares = function (arr) { arr.forEach(function (n) { console.log(n * n); }); }; 

Usando el map :

Tarea 2: Escribir una función selfDot , que acepta una matriz de números arr , y devuelve una matriz en la que cada elemento es el cuadrado del elemento correspondiente en arr .

Aparte: aquí, en términos de jerga, estamos tratando de cuadrar la matriz de entrada. Formalmente, estamos tratando de calcular su producto de puntos consigo mismo.

Solución 2:

 var selfDot = function (arr) { return arr.map(function (n) { return n * n; }); }; 

¿Cómo es el map un superconjunto de forEach ?

Puede usar el map para resolver ambas tareas, Tarea 1 y Tarea 2 . Sin embargo, no puede usar forEach para resolver la Tarea 2 .

En la Solución 1 , si simplemente reemplaza para forEach por un map , la solución seguirá siendo válida. Sin embargo, en la Solución 2 , al reemplazar el map por forEach se romperá la solución que ya forEach .

Implementando forEach en términos de map :

Otra forma de realizar la superioridad del map es implementar forEach en términos de map . Como somos buenos progtwigdores, no nos permitiremos la contaminación del espacio de nombres. Llamaremos a forEach , solo a each .

 Array.prototype.each = function (func) { this.map(func); }; 

Ahora, si no te gusta el prototype tonterías, aquí tienes:

 var each = function (arr, func) { arr.map(func); // Or map(arr, func); }; 

Entonces, umm … ¿Por qué existe forEach incluso?

La respuesta es eficiencia. Si no está interesado en transformar una matriz en otra matriz, ¿por qué debería calcular la matriz transformada? ¿Solo para botarlo? ¡Por supuesto no! Si no quieres una transformación, no debes hacer una transformación.

Entonces, aunque el mapa se puede usar para resolver la Tarea 1 , probablemente no debería. Para cada uno es el candidato adecuado para eso.


Respuesta original:

Si bien estoy de acuerdo en gran medida con la respuesta de @madlep, me gustaría señalar que map() es un súper conjunto estricto de forEach() .

Sí, map() se usa generalmente para crear una nueva matriz. Sin embargo, también se puede usar para cambiar la matriz actual.

Aquí hay un ejemplo:

 var a = [0, 1, 2, 3, 4], b = null; b = a.map(function (x) { a[x] = 'What!!'; return x*x; }); console.log(b); // logs [0, 1, 4, 9, 16] console.log(a); // logs ["What!!", "What!!", "What!!", "What!!", "What!!"] 

En el ejemplo anterior, a se configuró convenientemente de modo que a[i] === i para i < a.length . Aun así, demuestra el poder de map() .

Aquí está la descripción oficial de map() . Tenga en cuenta que map() puede incluso cambiar la matriz en la que se llama. Granizo map() .

Espero que esto haya ayudado.


Editado el 10 de noviembre de 2015: elaboración adicional.

Aquí hay un ejemplo en Scala usando listas: map returns list, foreach no devuelve nada.

 def map(f: Int ⇒ Int): List[Int] def foreach(f: Int ⇒ Unit): Unit 

Entonces map devuelve la lista resultante de aplicar la función f a cada elemento de la lista:

 scala> val list = List(1, 2, 3) list: List[Int] = List(1, 2, 3) scala> list map (x => x * 2) res0: List[Int] = List(2, 4, 6) 

Foreach simplemente aplica f a cada elemento:

 scala> var sum = 0 sum: Int = 0 scala> list foreach (sum += _) scala> sum res2: Int = 6 // res1 is empty 

Si hablamos de Javascript en particular, la diferencia es que el map es una función de bucle, mientras que para cada forEach es un iterador.

Utilice el map cuando desee aplicar una operación a cada miembro de la lista y obtenga los resultados como una nueva lista, sin afectar la lista original.

Use forEach cuando desee hacer algo en función de cada elemento de la lista. Puede agregar cosas a la página, por ejemplo. Básicamente, es ideal para cuando quieres “efectos secundarios”.

Otras diferencias: forEach no devuelve nada (ya que es realmente una función de flujo de control), y la función transferida obtiene referencias del índice y de toda la lista, mientras que map devuelve la nueva lista y solo pasa en el elemento actual.

Intereting Posts