Есть ли разница между foreach и map?
-
21-08-2019 - |
Вопрос
Хорошо, это скорее вопрос информатики, чем вопрос, основанный на определенном языке, но есть ли разница между операцией map и операцией foreach?Или это просто разные названия одной и той же вещи?
Решение
Другой.
foreach выполняет итерацию по списку и применяет некоторую операцию с побочными эффектами к каждому элементу списка (например, сохраняет каждый элемент в базе данных).
map выполняет итерацию по списку, преобразует каждый элемент этого списка и возвращает другой список того же размера с преобразованными элементами (например, преобразует список строк в верхний регистр).
Другие советы
Важное различие между ними заключается в том, что map
накапливает все результаты в коллекцию, тогда как foreach
ничего не возвращает. map
обычно используется, когда вы хотите преобразовать коллекцию элементов с помощью функции, тогда как foreach
просто выполняет действие для каждого элемента.
Короче говоря, foreach
предназначен для применения операции к каждому элементу коллекции элементов, тогда как map
предназначен для преобразования одной коллекции в другую.
Есть два существенных различия между foreach
и map
.
foreach
не имеет концептуальных ограничений на операцию, которую он применяет, за исключением, возможно, принятия элемента в качестве аргумента.То есть операция может ничего не делать, может иметь побочный эффект, может возвращать значение или не возвращать его.Всеforeach
заботится о том, чтобы выполнить итерацию по коллекции элементов и применить операцию к каждому элементу.map
, с другой стороны, имеет ограничение на операцию:он ожидает, что операция вернет элемент и, вероятно, также примет элемент в качестве аргумента.Вmap
операция выполняет итерацию по коллекции элементов, применяя операцию к каждому элементу и, наконец, сохраняя результат каждого вызова операции в другой коллекции.Другими словами,map
трансформирует одна коллекция переходит в другую.foreach
работает с одной коллекцией элементов.Это коллекция входных данных.map
работает с двумя наборами элементов:входная коллекция и выходная коллекция.
Это не ошибка - соотносить два алгоритма:фактически, вы можете рассматривать их иерархически, где map
является специализацией foreach
.То есть, вы могли бы использовать foreach
и пусть операция преобразует свой аргумент и вставляет его в другую коллекцию.Итак, в foreach
алгоритм - это абстракция, обобщение map
алгоритм.На самом деле, потому что foreach
не имеет никаких ограничений на свою работу, мы можем с уверенностью сказать, что foreach
это самый простой механизм зацикливания, и он может делать все, что может сделать цикл. map
, а также другие более специализированные алгоритмы, существуют для выразительности:если вы хотите отобразить (или преобразовать) одну коллекцию в другую, ваше намерение станет яснее, если вы используете map
чем если бы вы использовали foreach
.
Мы можем продолжить это обсуждение дальше и рассмотреть copy
алгоритм:цикл, который клонирует коллекцию.Этот алгоритм также является специализацией foreach
алгоритм.Вы могли бы определить операцию, которая, учитывая элемент, вставит этот же элемент в другую коллекцию.Если вы используете foreach
с помощью этой операции вы, по сути, выполнили copy
алгоритм, хотя и с пониженной ясностью, выразительностью или эксплицитностью.Давайте пойдем еще дальше:Мы можем сказать, что map
является специализацией copy
, сама по себе являющаяся специализацией foreach
. map
мочь изменение любой из элементов, по которым он повторяется.Если map
не изменяет ни один из элементов, то это просто скопированный элементы, и используя Копировать это позволило бы более четко выразить свое намерение.
В foreach
сам алгоритм может иметь или не иметь возвращаемое значение, в зависимости от языка.Например, в C ++, foreach
возвращает операцию, которую она первоначально получила.Идея заключается в том, что операция может иметь состояние, и вы можете захотеть вернуть эту операцию обратно, чтобы проверить, как она развивалась по элементам. map
, тоже может возвращать значение, а может и не возвращать.В C++ transform
(эквивалент для map
здесь) происходит возврат итератора в конец выходного контейнера (коллекции).В Ruby возвращаемое значение map
является выходной последовательностью (коллекцией).Таким образом, возвращаемое значение алгоритмов на самом деле является деталью реализации;их эффект может быть, а может и не быть тем, что они возвращают.
Array.protototype.map
способ & Array.protototype.forEach
оба они очень похожи.
Запустите следующий код: 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));
});
Они дают точный такой же результат.
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
Но поворот происходит, когда вы запускаете следующий код:-
Здесь я просто присвоил результат возвращаемого значения из методов map и forEach.
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();
Теперь в результате получается нечто хитрое!
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
Заключение
Array.prototype.map
возвращает массив, но Array.prototype.forEach
не делает.Таким образом, вы можете манипулировать возвращаемым массивом внутри функции обратного вызова, переданной методу map, а затем вернуть его.
Array.prototype.forEach
проходит только по заданному массиву, так что вы можете делать свои вещи во время обхода массива.
наиболее "заметным" отличием является то, что map накапливает результат в новой коллекции, в то время как foreach выполняется только для самого выполнения.
но есть пара дополнительных предположений:поскольку "целью" map является новый список значений, порядок выполнения на самом деле не имеет значения.фактически, некоторые среды выполнения генерируют параллельный код или даже вводят некоторое запоминание, чтобы избежать вызова повторяющихся значений, или леность, чтобы вообще избежать вызова некоторых.
с другой стороны, foreach вызывается специально для побочных эффектов;поэтому порядок важен и обычно не может быть распараллелен.
Короткий ответ: map
и forEach
они разные.Кроме того, неофициально говоря, map
является строгим надмножеством forEach
.
Длинный ответ: Во-первых, давайте составим однострочное описание forEach
и map
:
forEach
выполняет итерацию по всем элементам, вызывая предоставленную функцию для каждого.map
выполняет итерацию по всем элементам, вызывая предоставленную функцию для каждого, и создает преобразованный массив, запоминая результат каждого вызова функции.
На многих языках, forEach
часто называется просто each
.Следующее обсуждение использует JavaScript только для справки.Это действительно может быть любой другой язык.
Теперь давайте воспользуемся каждой из этих функций.
Используя forEach
:
Задача 1: Напишите функцию printSquares
, который принимает массив чисел arr
, и выводит квадрат каждого элемента в нем.
Решение 1:
var printSquares = function (arr) {
arr.forEach(function (n) {
console.log(n * n);
});
};
Используя map
:
Задача 2: Напишите функцию selfDot
, который принимает массив чисел arr
, и возвращает массив , в котором каждый элемент является квадратом соответствующего элемента в arr
.
В сторону:Здесь, выражаясь жаргонными терминами, мы пытаемся возвести входной массив в квадрат.Формально говоря, мы пытаемся вычислить его точечное произведение с самим собой.
Решение 2:
var selfDot = function (arr) {
return arr.map(function (n) {
return n * n;
});
};
Как это map
надмножество из forEach
?
Вы можете использовать map
для решения обеих задач, Задача 1 и Задача 2.Однако вы не можете использовать forEach
чтобы решить Задача 2.
В Решение 1, если вы просто замените forEach
Автор: map
, решение по-прежнему будет действительным.В Решение 2 однако, заменяя map
Автор: forEach
нарушит ваше ранее работавшее решение.
Реализующий forEach
с точки зрения map
:
Другой способ осознания map
превосходство заключается в реализации forEach
с точки зрения map
.Поскольку мы хорошие программисты, мы не будем потворствовать загрязнению пространства имен.Мы назовем наш forEach
, просто each
.
Array.prototype.each = function (func) {
this.map(func);
};
Теперь, если вам не нравится prototype
чепуха, вот ты где:
var each = function (arr, func) {
arr.map(func); // Or map(arr, func);
};
Итак, ммм..Почему это делает forEach
даже существовать?
Ответ заключается в эффективности.Если вы не заинтересованы в преобразовании массива в другой массив, зачем вам вычислять преобразованный массив?Только для того, чтобы выбросить это?Конечно, нет!Если вы не хотите трансформации, вам не следует ее проводить.
Таким образом, в то время как карта может быть использована для решения Задача 1, вероятно, этого не должно быть.Ибо каждый из них является подходящим кандидатом для этого.
Оригинальный ответ:
Хотя я в значительной степени согласен с ответом @madlep, я хотел бы отметить, что map()
является строгий супер-набор из forEach()
.
ДА, map()
обычно используется для создания нового массива.Однако это может также может использоваться для изменения текущего массива.
Вот пример:
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!!"]
В приведенном выше примере, a
был удобно установлен таким образом , что a[i] === i
для i < a.length
.Тем не менее, это демонстрирует силу map()
.
Вот официальное описание map()
.Обратите внимание , что map()
может даже изменить массив, для которого он вызывается!Приветствую map()
.
Надеюсь, это помогло.
Отредактировано 10 ноября 2015 г.:Добавлена проработка.
Вот пример использования списков в Scala:map возвращает список, foreach ничего не возвращает.
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
Таким образом, map возвращает список, полученный в результате применения функции f к каждому элементу списка:
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 просто применяет f к каждому элементу:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
Если вы говорите, в частности, о Javascript, разница в том, что map
является функцией цикла, в то время как forEach
является итератором.
Использование map
когда вы хотите применить операцию к каждому элементу списка и получить результаты обратно в виде нового списка, не затрагивая исходный список.
Использование forEach
когда ты захочешь делай что-то на основе каждого элемента списка.Например, вы можете добавлять что-то на страницу.По сути, это отлично подходит для тех случаев, когда вам нужны "побочные эффекты".
Другие различия: forEach
ничего не возвращает (поскольку это действительно функция потока управления), а переданная функция получает ссылки на индекс и весь список, тогда как map возвращает новый список и передает только текущий элемент.
ForEach пытается применить функцию, такую как запись в db и т.д., К каждому элементу RDD, ничего не возвращая обратно.
Но тот map()
применяет некоторую функцию к элементам rdd и возвращает rdd.Итак, когда вы запускаете приведенный ниже метод, он не завершится сбоем в строке 3, но при сборе rdd после применения foreach он завершится сбоем и выдаст ошибку, в которой говорится
Файл "<stdin>", строка 5, в <module>
Ошибка атрибута:Объект 'NoneType' не имеет атрибута 'collect'
nums = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
num2 = nums.map(lambda x: x+2)
print ("num2",num2.collect())
num3 = nums.foreach(lambda x : x*x)
print ("num3",num3.collect())