foreach和地图之间有区别吗?

时间:2008-12-10 02:09:29

标签: foreach language-agnostic computer-science map-function

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

8 个答案:

答案 0 :(得分:284)

不同。

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

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

答案 1 :(得分:118)

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

答案 2 :(得分:40)

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

foreachmap之间存在两个显着差异。

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

    另一方面,

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

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

    map使用两个元素集合:输入集合和输出集合。

  3. 将这两种算法联系起来并不是一个错误:实际上,您可以分层次地查看这两种算法,其中mapforeach的特化。也就是说,您可以使用foreach并让操作转换其参数并将其插入另一个集合中。因此,foreach算法是map算法的抽象概括。事实上,因为foreach对其操作没有限制,我们可以有把握地说foreach是最简单的循环机制,并且它可以做循环可以做的任何事情。 map,以及其他更专业的算法,是表达性的:如果你想将一个集合映射(或转换)到另一个集合,如果你使用map,你的意图比你使用{更明确{1}}。

    我们可以进一步扩展这个讨论,并考虑foreach算法:克隆集合的循环。该算法也是copy算法的特化。您可以定义一个操作,给定一个元素,将该元素插入另一个集合中。如果您使用foreach进行该操作,则实际上执行了foreach算法,尽管清晰度,表现力或表现力都有所降低。让我们更进一步:我们可以说copymap的特化,本身是copy的特化。 foreach可以更改它迭代的任何元素。如果map没有更改任何元素,那么它只是复制元素,而使用 copy 会更清楚地表达意图。

    map算法本身可能有也可能没有返回值,具体取决于语言。例如,在C ++中,foreach返回它最初收到的操作。这个想法是操作可能有一个状态,你可能希望该操作回来检查它是如何在元素上进化的。 foreach也可能会或可能不会返回值。在C ++ map(此处为transform的等价物)碰巧将迭代器返回到输出容器(集合)的末尾。在Ruby中,map的返回值是输出序列(集合)。因此,算法的返回值实际上是一个实现细节;他们的影响可能是也可能不是他们的回归。

答案 3 :(得分:30)

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只遍历给定的数组,这样你就可以在走阵列时做你的事了。

答案 4 :(得分:11)

最“可见”的区别在于,map会将结果累积到新集合中,而foreach仅针对执行本身进行。

但还有一些额外的假设:由于map的'目的'是新的值列表,因此执行的顺序并不重要。事实上,一些执行环境生成并行代码,甚至引入一些memoizing以避免调用重复值或者懒惰,以避免调用某些代码。

另一方面,foreach被称为副作用;因此,顺序很重要,通常不能并行化。

答案 5 :(得分:11)

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

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

  • 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数组,并返回一个数组,其中每个元素都是{中对应元素的平方{1}}。

旁白:在这里,在俚语中,我们试图对输入数组进行平方。正式地说,我们正试图用它自己来计算它的点积。

解决方案2:

arr

var selfDot = function (arr) { return arr.map(function (n) { return n * n; }); }; 如何成为map的超集?

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

解决方案1 ​​中,如果您只是将forEach替换为forEach,则解决方案仍然有效。但是,在解决方案2 中,将map替换为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); }; 甚至存在?

答案是效率。如果您对将数组转换为另一个数组不感兴趣,为什么要计算转换后的数组呢?只是为了转储它?当然不是!如果你不想进行转型,你就不应该进行转型。

因此,虽然map可用于解决任务1 ,但它可能不应该。因为每个人都是合适的人选。


原始答案:

虽然我基本同意@madlep的回答,但我想指出forEachmap()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()的力量。

Here's the official description of map()。请注意,map()甚至可能会更改调用它的数组! Hail map()

希望这会有所帮助。


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

答案 6 :(得分: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

答案 7 :(得分:2)

如果您特别谈论Javascript,区别在于map是循环函数,而forEach是迭代器。

如果要将操作应用于列表的每个成员并将结果作为新列表返回,请使用map,而不会影响原始列表。

如果您希望根据列表的每个元素执行某事,请使用forEach。例如,您可能正在向页面添加内容。从本质上讲,当你想要“副作用”时它非常棒。

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