foreach和map有区别吗?
好吧,这是一个计算机科学问题,而不是一个基于特定语言的问题,但是地图操作和foreach操作之间有什么区别吗? 或者他们只是同一个事物的不同名称?
不同。
foreach遍历一个列表,并对每个列表成员应用一些带有副作用的操作(例如,将每个列表成员保存到数据库中)
map遍历列表,转换该列表的每个成员,并返回与转换的成员具有相同大小的另一个列表(例如将string列表转换为大写)
他们之间的重要区别是, map
所有结果累积到一个集合中,而foreach
返回任何结果。 当你想用一个函数来转换元素的集合时,通常会使用map
,而foreach
只是为每个元素执行一个操作。
简而言之, foreach
是对元素集合中的每个元素应用一个操作,而map
则是将一个集合转换为另一个集合。
foreach
和map
之间有两个显着的区别。
-
除了可能接受一个元素作为参数之外,
foreach
对它所应用的操作没有概念上的限制。 也就是说,这个操作可能什么都不做,可能有副作用,可能返回一个值或者可能不会返回一个值。 所有foreach
关心的是迭代一组元素,并在每个元素上应用操作。另一方面,
map
对操作有一个限制:它期望操作返回一个元素,也可能接受一个元素作为参数。map
操作迭代元素集合,对每个元素应用操作,最后将每个操作的调用结果存储到另一个集合中。 换句话说,map
将一个集合转换为另一个集合。 -
foreach
与单个元素集合一起工作。 这是input集合。map
与两个元素集合一起工作:input集合和输出集合。
将这两种algorithm联系起来并不是一个错误:事实上,您可以分层次地查看这两个map
,其中map
是foreach
的专业化版本。 也就是说,你可以使用foreach
并让操作转换它的参数并将其插入到另一个集合中。 所以, foreach
algorithm是map
algorithm的一个抽象概括。 事实上,由于foreach
对其运行没有限制,我们可以放心地说, foreach
是最简单的循环机制,它可以做任何循环都能做的事情。 map
,以及其他更专业的algorithm,有performance力:如果你想映射(或转换)一个集合到另一个,你的意图是清晰的,如果你使用map
不是你使用foreach
。
我们可以进一步扩展这个讨论,并考虑copy
algorithm:一个克隆集合的循环。 这个algorithm也是foreach
algorithm的一个专门化。 你可以定义一个操作,给定一个元素,将相同的元素插入到另一个集合中。 如果使用该操作的foreach
,则实际上会执行copy
algorithm,尽pipe清晰度,performance力或清晰度都较低。 让我们更进一步:我们可以说, map
是copy
的专业化,本身就是foreach
的专业化。 map
可能会改变它迭代的任何元素。 如果map
不改变任何元素,那么它只是复制元素,使用复制将更清楚地expression意图。
foreach
algorithm本身可能有也可能没有返回值,这取决于语言。 例如,在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被专门称为副作用; 所以顺序很重要,通常不能平行。
简答: map
和forEach
是不同的。 另外,非正式地说, map
是forEach
一个严格的超集。
长答案:首先,让我们拿出forEach
和map
一行描述:
-
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中 ,如果您只是简单地用map
replaceforEach
,那么解决scheme仍然有效。 然而,在解决scheme2中,用forEach
replacemap
将会破坏以前的工作解决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则返回新的列表并且只传入当前元素。