foreach和map之间有区别吗?


218

好的,这更多是计算机科学问题,而不是基于特定语言的问题,但是map操作和foreach操作之间有区别吗?还是它们只是同一事物的不同名称?


奇怪的是,如果我得到一个Iterator[String]scala.io.Source.fromFile("/home/me/file").getLines()并应用.foreach(s => ptintln(s))它,它是印刷好的,但得到之后空的权利。同时,如果我申请.map(ptintln(_))它,它只会变空并且什么也不会打印。
伊万(Ivan)2012年

Answers:


294

不同。

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

map遍历一个列表,转换该列表的每个成员,然后返回与转换后的成员大小相同的另一个列表(例如将字符串列表转换为大写)


谢谢,我以为是这些事情,但不确定!
罗伯特·古尔德

19
但您也可能在map函数中发生副作用。我喜欢这个答案:stackoverflow.com/a/4927981/375688
TinyTimZamboni 2014年

6
很重要的一点提(这是尤其如此斯卡拉)是一个电话map没有导致它的基本逻辑的执行当预期转化列表被召唤到。相反,foreach的运算是立即计算的。
bigT 2016年

124

它们之间的重要区别是将map所有结果累加到一个集合中,而foreach什么都不返回。map通常在您要使用函数转换元素集合时使用,而foreach仅对每个元素执行一个动作。


谢谢!现在我明白了区别。这对我来说已经相当模糊了
罗伯特·古尔德

也很重要!
МатиТернер

40

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

foreach和之间有两个重要区别map

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

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

  2. foreach使用单个元素集合。这是输入集合。

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

关联这两种算法不是错:实际上,您可以按层次结构查看这两种算法,其中的特化mapforeach。也就是说,您可以使用foreach并使该操作转换其参数并将其插入到另一个集合中。因此,该foreach算法是该算法的抽象,概括map。实际上,由于foreach对其操作没有限制,我们可以放心地说这foreach是最简单的循环机制,它可以完成循环可以做的任何事情。map以及其他更专门的算法可用于表达:如果您希望将一个集合映射(或转换)为另一个集合,那么使用的目的就map比使用的要明确foreach

我们可以进一步扩展讨论,并考虑copy算法:克隆集合的循环。该算法也是该算法的一种特殊化foreach。您可以定义一个操作,给定一个元素,该操作会将同一元素插入另一个集合中。如果foreach与该操作一起使用,则实际上会执行该copy算法,尽管会降低其清晰度,表现力或显式性。让我们更进一步:我们可以说这map是的专业化copy,本身是的专业化foreachmap可能会更改其迭代的任何元素。如果map不更改任何元素,则仅复制元素,然后使用复制 会更清楚地表达意图。

foreach算法本身可能会或可能不会有一个返回值,根据语言。例如,在C ++中,foreach返回其最初接收的操作。想法是该操作可能具有状态,您可能希望该操作返回以检查其在元素上的演变方式。map,也可能会或可能不会返回值。在C ++中transformmap此处等效),恰好将迭代器返回到输出容器(集合)的末尾。在Ruby中,返回值map是输出序列(集合)。因此,算法的返回值实际上是一个实现细节。它们的效果可能是也可能不是返回的结果。


有关如何.forEach()实现的示例.map(),请参见此处:stackoverflow.com/a/39159854/1524693
Chinoto Vokro,2016年

32

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.forEach 只遍历给定的数组,因此您可以在遍历数组的同时做自己的事情。


11

最“可见”的区别是,映射将结果累积到一个新的集合中,而foreach仅针对执行本身完成。

但是还有两个额外的假设:由于map的“目的”是新的值列表,因此执行顺序实际上并不重要。实际上,某些执行环境会生成并行代码,甚至会引入一些备忘录,以避免调用重复的值或延迟,从而避免调用任何代码。

另一方面,foreach是专门针对副作用的;因此顺序很重要,通常不能并行化。


11

简短的回答: mapforEach有所不同。另外,从非正式角度来说,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中,如果仅替换forEachmap,则该解决方案仍然有效。但是,在解决方案2中,替换mapforEach将会破坏您以前使用的解决方案。

实施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甚至存在?

答案是效率。如果您对将一个数组转换为另一个数组不感兴趣,为什么要计算转换后的数组?只能丢了吗?当然不是!如果您不想进行转换,则不应进行转换。

因此,虽然可以使用map解决任务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] === ii < a.length。即便如此,它仍显示的力量map()

这是的正式说明map()。请注意,它map()甚至可能会更改其所在的数组!冰雹map()

希望这会有所帮助。


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


-1,因为这仅在javascript下有效;该问题专门讨论语言不可知论和计算机科学概念,而不是有限的实现。
哈维尔

1
@Javier:嗯..我必须就我的答案针对JavaScript达成一致。但是请问自己:语言是否具有本机map功能,但没有forEach?您不能简单地不使用map代替forEach吗?在另一面,如果语言有forEach,但没有map,你就必须实现自己的map。您不能简单地使用forEach而不是map。告诉我你的想法。
Sumukh Barve 2015年

3

这是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

2

如果您特别在谈论Javascript,则不同之处在于这map是一个循环函数,而forEach而是一个迭代器。

map时要应用的操作列表中的每个成员,并获得满意的结果早在新的列表,在不影响原有的列表中。

使用forEach时要做到基于列表的每个元素某项操作。例如,您可能正在向页面添加内容。本质上,当您需要“副作用”时,它非常有用。

其他区别:forEach什么都不返回(因为它实际上是一个控制流函数),并且传入的函数获取对索引和整个列表的引用,而map返回新列表,并且仅传递当前元素。


0

ForEach尝试在RDD的每个元素上应用诸如写入db等功能,而不返回任何内容。

但是map()apply将一些函数应用于rdd的元素并返回rdd。因此,当您运行以下方法时,它不会在第3行失败,但是在申请foreach之后收集rdd时,它将失败并抛出错误,

<模块>中第5行的文件“ <stdin>”

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())
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.