好吧,这更像是一个计算机科学问题,而不是一个基于特定语言的问题,但是map操作和foreach操作之间有区别吗?或者它们只是同一事物的不同名称?
不同。
foreach遍历列表,执行对每个列表成员执行一些有副作用的操作(例如将每个成员保存到数据库)
map遍历一个列表,转换该列表的每个成员,并返回另一个具有已转换成员的相同大小的列表(例如将字符串列表转换为大写)
它们之间的重要区别是map将所有结果累积到一个集合中,而foreach不返回任何结果。map通常用于想要用函数转换元素集合时,而foreach只是为每个元素执行一个操作。
map
foreach
如果你特别谈论Javascript,区别在于map是一个循环函数,而forEach是一个迭代器。
forEach
当你想对列表的每个成员应用操作并将结果作为一个新列表返回时,使用map,而不影响原始列表。
当你想在列表的每个元素的基础上做某项时,使用forEach。例如,您可能正在向页面添加内容。从本质上讲,当你想要“副作用”时,它是很好的。
其他区别:forEach不返回任何东西(因为它实际上是一个控制流函数),传入函数获得对索引和整个列表的引用,而map返回新列表,只传入当前元素。
最“明显”的区别是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没有改变任何元素,那么它只是foreach0元素,使用foreach1将更清楚地表达意图。
copy
foreach算法本身可能有也可能没有返回值,这取决于语言。例如,在c++中,foreach返回它最初接收到的操作。其思想是,操作可能有一个状态,您可能希望返回该操作以检查它是如何在元素中演化的。map也可能返回值,也可能不返回值。在c++中,transform(这里等价于map)恰好返回一个指向输出容器(集合)末尾的迭代器。在Ruby中,map的返回值是输出序列(集合)。所以,算法的返回值实际上是一个实现细节;它们的效果可能是,也可能不是它们的回报。
transform
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方法的回调函数中操作返回的数组,然后返回它。
Array.prototype.map
Array.prototype.forEach
Array.prototype.forEach只遍历给定的数组,所以你可以在遍历数组时做你的事情。
下面是一个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
简短的回答: map和forEach是不同的。另外,非正式地说,map是forEach的严格超集。
首先,让我们给出forEach和map的一行描述:
在许多语言中,forEach通常被称为each。下面的讨论使用JavaScript仅供参考。它真的可以是任何其他语言。
each
现在,让我们分别使用这些函数。
写一个函数printSquares,它接受一个数字数组arr,并打印其中每个元素的平方。
printSquares
arr
解决方案1:
var printSquares = function (arr) { arr.forEach(function (n) { console.log(n * n); }); };
写一个函数selfDot,它接受数字数组arr,并返回一个数组,其中每个元素都是arr中相应元素的平方。
selfDot
旁白:在这里,在俚语中,我们试图平方输入数组。正式地说,我们试着计算它与自身的点积。
解决方案2:
var selfDot = function (arr) { return arr.map(function (n) { return n * n; }); };
你可以使用map来解决这两个任务,任务1和任务2。然而,你不能使用forEach来解决任务2。
在解决方案1中,如果你简单地将forEach替换为map,解决方案仍然有效。然而,在解决方案2中,用forEach替换map将破坏你之前的工作解决方案。
实现map优势的另一种方法是根据map实现forEach。由于我们是优秀的程序员,我们不会沉迷于名称空间污染。我们将forEach命名为each。
Array.prototype.each = function (func) { this.map(func); };
现在,如果你不喜欢prototype的废话,在这里:
prototype
var each = function (arr, func) { arr.map(func); // Or map(arr, func); };
答案是效率。如果您对将一个数组转换为另一个数组不感兴趣,为什么要计算转换后的数组呢?只是为了把它扔掉?当然不是!如果你不想做变换,你就不应该做变换。
因此,虽然map可以用来解决任务1,它可能不应该。因为每个人都是正确的候选人。
虽然我在很大程度上同意@madlep的回答,但我想指出,map()是forEach()的严格的超集。
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被方便地设置为i < a.length的a[i] === i。即便如此,它也展示了map()的强大功能。
a
i < a.length
a[i] === i
下面是map()的官方描述。注意map()甚至可以改变调用它的数组!冰雹map()。
希望这对你有所帮助。
编辑2015年11月10日:增加详细说明。
ForEach尝试在RDD的每个元素上应用一个函数,比如写入db等,而不返回任何东西。
但是map()在rdd的元素上应用了一些函数并返回rdd。所以当你运行下面的方法时,它不会在第3行失败,但在应用foreach后收集rdd时,它会失败并抛出一个错误
文件“<stdin>"”,第5行,在<module> AttributeError: 'NoneType'对象没有collect属性
文件“<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())