Есть ли разница между foreach и map? - PullRequest
211 голосов
/ 10 декабря 2008

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

Ответы [ 9 ]

284 голосов
/ 10 декабря 2008

Different.

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

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

118 голосов
/ 10 декабря 2008

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

40 голосов
/ 29 мая 2010

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

Сам алгоритм foreach может иметь или не иметь возвращаемое значение, в зависимости от языка. Например, в C ++ foreach возвращает первоначально полученную операцию. Идея состоит в том, что операция может иметь состояние, и вы можете захотеть, чтобы эта операция вернулась, чтобы проверить, как она развивалась над элементами. map тоже может возвращать или не возвращать значение. В C ++ transform (эквивалент map здесь) происходит возврат итератора в конец выходного контейнера (коллекции). В Ruby возвращаемое значение map является выходной последовательностью (коллекцией). Таким образом, возвращаемое значение алгоритмов действительно является деталью реализации; их эффект может быть или не быть тем, что они возвращают.

30 голосов
/ 29 января 2013

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

11 голосов
/ 29 июля 2014

Краткий ответ: 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, решение останется в силе. Однако в Solution 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 голосов
/ 10 декабря 2008

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

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

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

3 голосов
/ 13 мая 2014

Вот пример в Scala, использующий списки: карта возвращает список, foreach ничего не возвращает.

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

Таким образом, карта возвращает список, полученный в результате применения функции 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
2 голосов
/ 10 декабря 2008

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

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

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

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

0 голосов
/ 11 марта 2019

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

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

Файл "", строка 5, в

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())
...