it-roy-ru.com

Есть ли разница между foreach и map?

Хорошо, это больше вопрос информатики, чем вопрос, основанный на конкретном языке, но есть ли разница между операцией отображения и операцией foreach? Или это просто разные имена для одной и той же вещи?

211
Robert Gould

Разные.

foreach выполняет итерацию по списку и применяет некоторые операции с побочными эффектами к каждому члену списка (например, сохранение каждого из них в базе данных)

map выполняет итерации по списку, преобразует каждого члена этого списка и возвращает другой список того же размера с преобразованными членами (например, преобразование списка строк в верхний регистр)

284
madlep

Важное различие между ними состоит в том, что map накапливает все результаты в коллекцию, тогда как foreach ничего не возвращает. map обычно используется, когда вы хотите преобразовать коллекцию элементов с помощью функции, тогда как foreach просто выполняет действие для каждого элемента.

118
Henk

Вкратце, foreach предназначен для применения операции к каждому элементу коллекции элементов, тогда как map предназначен для преобразования одной коллекции в другую.

Между foreach и map есть два существенных различия.

  1. foreach не имеет концептуальных ограничений на применяемую операцию, за исключением, возможно, принятия элемента в качестве аргумента. То есть операция может ничего не делать, может иметь побочный эффект, может возвращать значение или может не возвращать значение. Все, что foreach заботится о том, чтобы перебрать коллекцию элементов и применить операцию к каждому элементу.

    map, с другой стороны, имеет ограничение на операцию: она ожидает, что операция вернет элемент, и, вероятно, также примет элемент в качестве аргумента. Операция map перебирает коллекцию элементов, применяя операцию к каждому элементу и, наконец, сохраняя результат каждого вызова операции в другой коллекции. Другими словами, mapпреобразует одну коллекцию в другую.

  2. 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 является выходной последовательностью (коллекцией). Таким образом, возвращаемое значение алгоритмов действительно является деталью реализации; их эффект может быть или не быть тем, что они возвращают.

40
wilhelmtell

Метод 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

Но поворот происходит, когда вы запускаете следующий код:

Здесь я просто присвоил результат возвращаемого значения из карты и методы 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 только проходит по указанному массиву, чтобы вы могли делать свои вещи во время обхода массива.

30
abhisekp

Краткий ответ: 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: добавлена ​​разработка.

11
Sumukh Barve

наиболее "видимое" отличие состоит в том, что map накапливает результат в новой коллекции, тогда как foreach выполняется только для самого выполнения.

но есть несколько дополнительных предположений: поскольку "назначение" карты - это новый список значений, на самом деле не имеет значения порядок выполнения. на самом деле, некоторые среды исполнения генерируют параллельный код или даже вводят некоторую запоминание, чтобы избежать вызова повторяющихся значений или лени, чтобы вообще не вызывать некоторые.

foreach, с другой стороны, вызывается специально для побочных эффектов; поэтому порядок важен и обычно не может быть распараллелен.

11
Javier

Вот пример использования Scala списков: карта возвращает список, 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
3
irudyak

Если вы говорите, в частности, о Javascript, то разница в том, что map - это функция цикла, а forEach - итератор.

Используйте map, когда вы хотите применить операцию к каждому члену списка и вернуть результаты в виде нового списка, не затрагивая первоначальный список.

Используйте forEach, когда вы хотите сделать что-то на основе каждого элемента списка. Вы можете добавлять вещи на страницу, например. По сути, это здорово, когда вам нужны "побочные эффекты".

Другие различия: forEach ничего не возвращает (так как это действительно функция потока управления), и переданная функция получает ссылки на индекс и весь список, тогда как map возвращает новый список и передает только текущий элемент.

2
phyzome

ForEach пытается применить функцию, такую ​​как запись в db и т.д., К каждому элементу СДР, не возвращая ничего обратно.

Но map() применяет некоторую функцию к элементам rdd и возвращает rdd. Поэтому, когда вы запустите приведенный ниже метод, он не завершится с ошибкой в ​​строке 3, но при сборе rdd после применения foreach он завершится ошибкой и выдаст сообщение об ошибке

Файл "<stdin>", строка 5, в <module>

AttributeError: у объекта '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())
0
user2456047