Гаразд, це скоріше питання інформатики, ніж питання, засноване на певній мові, але чи є різниця між операцією на карті та операцією foreach? Або вони просто різні назви для однієї речі?
Гаразд, це скоріше питання інформатики, ніж питання, засноване на певній мові, але чи є різниця між операцією на карті та операцією foreach? Або вони просто різні назви для однієї речі?
Відповіді:
Інший.
foreach ітераціює над списком і застосовує певну операцію з побічними ефектами до кожного члена списку (наприклад, збереження кожного в базі даних, наприклад)
карта повторює список, перетворює кожного члена цього списку і повертає інший список такого ж розміру з перетвореними членами (наприклад, перетворення списку рядків у великі регістри)
map
не чинить , НЕ призводить до виконання лежачих в його основі логіки , поки коли очікуваний трансформуються список викликається. На відміну від цього, foreach
операція обчислюється негайно.
Важлива відмінність між ними полягає в тому, що 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
- це вихідна послідовність (колекція). Отже, повернене значення алгоритмів - це насправді деталь реалізації; їх ефект може бути, а може бути і не тим, що вони повертають.
.forEach()
можна використовувати для реалізації .map()
, дивіться тут: stackoverflow.com/a/39159854/1524693
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
проходить лише через заданий масив, щоб ви могли робити свої речі під час прогулянки по масиву.
Найбільш «видима» різниця полягає в тому, що карта накопичує результат у новій колекції, тоді як передбачення робиться лише для самого виконання.
але є кілька додаткових припущень: оскільки «мета» карти є новим списком значень, це насправді не має значення порядку виконання. насправді, деякі середовища виконання генерують паралельний код, або навіть вводять деяке запам'ятовування, щоб уникнути виклику повторних значень чи ліні, щоб взагалі не викликати виклики.
З іншого боку, 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 «s, я хотів би зазначити, що 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 р.: Додано уточнення.
map
функцію, але ні forEach
; ви не могли просто не використовувати map
замість цього forEach
? З іншого боку, якби мова мала, forEach
але ні map
, вам доведеться реалізувати свою власну map
. Ви не можете просто використовувати forEach
замість цього map
. Скажи мені, що ти думаєш.
Ось приклад у 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
Якщо ви говорите саме про Javascript, різниця полягає в тому, що map
це циклічна функціяforEach
це ітератор.
Використовуйте map
коли ви хочете застосувати операцію до кожного учасника списку і повернути результати як новий список, не впливаючи на вихідний список.
Використовуйте, forEach
коли хочете зробити щось на основі кожного елемента списку. Ви можете, наприклад, додавати речі на сторінку. По суті, це чудово підходить, коли ви хочете "побічні ефекти".
Інші відмінності: forEach
нічого не повертає (оскільки це дійсно функція потоку управління), а функція, що передається, отримує посилання на індекс та весь список, тоді як карта повертає новий список і передає лише поточний елемент.
ForEach намагається застосувати таку функцію, як запис у db тощо на кожен елемент RDD, не повертаючи нічого назад.
Але map()
застосовує деяку функцію над елементами rdd і повертає rdd. Отже, коли ви запускаєте наведений нижче метод, він не вийде з рядка 3, але при збиранні rdd після застосування foreach він вийде з ладу і видасть помилку, яка говорить
Файл "<stdin>", рядок 5, в <module>
AttributeError: У об’єкта "NoneType" немає атрибута "збирати"
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())
Iterator[String]
відscala.io.Source.fromFile("/home/me/file").getLines()
і застосувати.foreach(s => ptintln(s))
до нього, він це спрацює , але порожніє відразу після. У той же час, якщо я звертаюся.map(ptintln(_))
до нього - він просто порожній і нічого не друкується.