foreach和map有区别吗?

好吧,这是一个计算机科学问题,而不是一个基于特定语言的问题,但是地图操作和foreach操作之间有什么区别吗? 或者他们只是同一个事物的不同名称?

不同。

foreach遍历一个列表,并对每个列表成员应用一些带有副作用的操作(例如,将每个列表成员保存到数据库中)

map遍历列表,转换该列表的每个成员,并返回与转换的成员具有相同大小的另一个列表(例如将string列表转换为大写)

他们之间的重要区别是, map所有结果累积到一个集合中,而foreach返回任何结果。 当你想用一个函数来转换元素的集合时,通常会使用map ,而foreach只是为每个元素执行一个操作。

简而言之, foreach是对元素集合中的每个元素应用一个操作,而map则是将一个集合转换为另一个集合。

foreachmap之间有两个显着的区别。

  1. 除了可能接受一个元素作为参数之外, foreach对它所应用的操作没有概念上的限制。 也就是说,这个操作可能什么都不做,可能有副作用,可能返回一个值或者可能不会返回一个值。 所有foreach关心的是迭代一组元素,并在每个元素上应用操作。

    另一方面, map对操作有一个限制:它期望操作返回一个元素,也可能接受一个元素作为参数。 map操作迭代元素集合,对每个元素应用操作,最后将每个操作的调用结果存储到另一个集合中。 换句话说, map 一个集合转换为另一个集合。

  2. foreach与单个元素集合一起工作。 这是input集合。

    map与两个元素集合一起工作:input集合和输出集合。

将这两种algorithm联系起来并不是一个错误:事实上,您可以分层次地查看这两个map ,其中mapforeach的专业化版本。 也就是说,你可以使用foreach并让操作转换它的参数并将其插入到另一个集合中。 所以, foreachalgorithm是mapalgorithm的一个抽象概括。 事实上,由于foreach对其运行没有限制,我们可以放心地说, foreach是最简单的循环机制,它可以做任何循环都能做的事情。 map ,以及其他更专业的algorithm,有performance力:如果你想映射(或转换)一个集合到另一个,你的意图是清晰的,如果你使用map不是你使用foreach

我们可以进一步扩展这个讨论,并考虑copyalgorithm:一个克隆集合的循环。 这个algorithm也是foreachalgorithm的一个专门化。 你可以定义一个操作,给定一个元素,将相同的元素插入到另一个集合中。 如果使用该操作的foreach ,则实际上会执行copyalgorithm,尽pipe清晰度,performance力或清晰度都较低。 让我们更进一步:我们可以说, mapcopy的专业化,本身就是foreach的专业化。 map可能会改变它迭代的任何元素。 如果map不改变任何元素,那么它只是复制元素,使用复制将更清楚地expression意图。

foreachalgorithm本身可能有也可能没有返回值,这取决于语言。 例如,在C ++中, foreach返回它原来收到的操作。 这个想法是,操作可能有一个状态,你可能希望这个操作回来检查它是如何演化的元素。 map也可能会返回一个值。 在C ++ transform (这里的map等价物)恰好将迭代器返回到输出容器(collection)的末尾。 在Ruby中, map的返回值是输出序列(collection)。 所以algorithm的返回值实际上是一个实现细节, 他们的效果可能会或可能不会是他们的回报。

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方法的callback函数中操作返回的数组,然后返回它。

Array.prototype.forEach只遍历给定的数组,所以你可以在走arrays时做你的东西。

最显而易见的区别是map将结果存储在一个新的集合中,而foreach只是为了执行本身。

但是还有一些额外的假设:由于map的“目的”是新的值列表,所以执行顺序并不重要。 实际上,一些执行环境会生成并行代码,甚至会引入一些记忆,以避免重复值或懒惰,以避免调用一些。

另一方面,foreach被专门称为副作用; 所以顺序很重要,通常不能平行。

简答: mapforEach是不同的。 另外,非正式地说, mapforEach一个严格的超集。

长答案:首先,让我们拿出forEachmap一行描述:

  • forEach遍历所有元素,调用每个提供的函数。
  • map遍历所有元素,在每个元素上调用提供的函数,并通过记住每个函数调用的结果来生成一个变换数组。

在许多语言中, forEach通常被称为each 。 以下讨论仅使用JavaScript作为参考。 它确实可以是任何其他语言。

现在,让我们使用这些函数中的每一个。

使用forEach

任务1:写一个函数printSquares ,它接受一个数组arr ,并打印每个元素的正方形。

解决scheme1:

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

使用map

任务2:编写一个函数selfDot ,它接受一个数组arr ,并返回一个数组,其中每个元素是arr相应元素的平方。

另外:在这里,用俚语来说,我们试图平方input数组。 forms上,我们正试图计算它自己的点积。

解决scheme2:

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

map如何成为forEach的超集?

您可以使用map来解决任务1任务2 。 但是,您无法使用forEach来解决任务2

解决scheme1中 ,如果您只是简单地用mapreplaceforEach ,那么解决scheme仍然有效。 然而,在解决scheme2中,用forEachreplacemap将会破坏以前的工作解决scheme。

map实现forEach

另一种实现map优势的方法是在map上实现forEach 。 由于我们是优秀的程序员,我们不会沉迷于命名空间污染。 我们会打电话给我们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()通常用于创build一个新的数组。 但是,它可能用于更改当前数组。

这是一个例子:

 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 。 即使如此,它也certificate了map()的强大function。

这是map()的官方描述 。 请注意, map()甚至可以改变它被调用的数组! 冰雹map()

希望这有助于。


2015年11月10日编辑:增加详细说明。

下面是使用列表的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返回任何东西(因为它实际上是一个控制stream函数),并且传入的函数获取对索引和整个列表的引用,而map则返回新的列表并且只传入当前元素。