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


不同。

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

Map遍历一个列表,转换该列表的每个成员,并返回另一个具有已转换成员的相同大小的列表(例如将字符串列表转换为大写)


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


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

当您希望对列表的每个成员应用操作并将结果作为新列表返回时,使用map,而不影响原始列表。

当您想在列表的每个元素的基础上做一些事情时,请使用forEach。例如,您可能正在向页面添加内容。从本质上讲,当你想要“副作用”时,它是很好的。

其他区别:forEach不返回任何内容(因为它实际上是一个控制流函数),传入函数获得对索引和整个列表的引用,而map返回新的列表,只传入当前元素。


最“明显”的区别是map将结果累积到一个新的集合中,而foreach仅用于执行本身。

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

另一方面,Foreach是专门用于副作用的;因此顺序很重要,而且通常不能并行。


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

foreach和map之间有两个显著的区别。

foreach has no conceptual restrictions on the operation it applies, other than perhaps accept an element as argument. That is, the operation may do nothing, may have a side-effect, may return a value or may not return a value. All foreach cares about is to iterate over a collection of elements, and apply the operation on each element. map, on the other hand, does have a restriction on the operation: it expects the operation to return an element, and probably also accept an element as argument. The map operation iterates over a collection of elements, applying the operation on each element, and finally storing the result of each invocation of the operation into another collection. In other words, the map transforms one collection into another. foreach works with a single collection of elements. This is the input collection. map works with two collections of elements: the input collection and the output collection.

It is not a mistake to relate the two algorithms: in fact, you may view the two hierarchically, where map is a specialization of foreach. That is, you could use foreach and have the operation transform its argument and insert it into another collection. So, the foreach algorithm is an abstraction, a generalization, of the map algorithm. In fact, because foreach has no restriction on its operation we can safely say that foreach is the simplest looping mechanism out there, and it can do anything a loop can do. map, as well as other more specialized algorithms, is there for expressiveness: if you wish to map (or transform) one collection into another, your intention is clearer if you use map than if you use foreach.

We can extend this discussion further, and consider the copy algorithm: a loop which clones a collection. This algorithm too is a specialization of the foreach algorithm. You could define an operation that, given an element, will insert that same element into another collection. If you use foreach with that operation you in effect performed the copy algorithm, albeit with reduced clarity, expressiveness or explicitness. Let's take it even further: We can say that map is a specialization of copy, itself a specialization of foreach. map may change any of the elements it iterates over. If map doesn't change any of the elements then it merely copied the elements, and using copy would express the intent more clearly.

The foreach algorithm itself may or may not have a return value, depending on the language. In C++, for example, foreach returns the operation it originally received. The idea is that the operation might have a state, and you may want that operation back to inspect how it evolved over the elements. map, too, may or may not return a value. In C++ transform (the equivalent for map here) happens to return an iterator to the end of the output container (collection). In Ruby, the return value of map is the output sequence (collection). So, the return value of the algorithms is really an implementation detail; their effect may or may not be what they return.


array . prototype .map方法和array . prototype . 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方法的回调函数中操作返回的数组,然后返回它。

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遍历所有元素,在每个元素上调用所提供的函数。 Map遍历所有元素,在每个元素上调用所提供的函数,并通过记住每个函数调用的结果来生成转换后的数组。

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

现在,让我们分别使用这些函数。

使用forEach:

任务1:编写printSquares函数,该函数接受数字数组arr,并打印其中每个元素的平方。

解决方案1:

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

使用地图:

任务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中,如果简单地用map替换forEach,解决方案仍然有效。然而,在解决方案2中,用forEach替换map将破坏之前的工作解决方案。

在map方面实现forEach:

实现map优势的另一种方法是根据map实现forEach。由于我们是优秀的程序员,我们不会沉迷于名称空间污染。我们将调用forEach。

Array.prototype.each = function (func) {
    this.map(func);
};

现在,如果你不喜欢毫无意义的原型,你可以这样做:

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] === i对于i < a.length。尽管如此,它还是展示了map()的强大功能。

下面是map()的官方描述。注意map()甚至可能改变调用它的数组!冰雹(地图)。

希望这对你有所帮助。


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


ForEach尝试在RDD的每个元素上应用一个函数,比如写入db等,而不返回任何东西。

但是map()在rdd的元素上应用一些函数并返回rdd。所以当你运行下面的方法时,它不会在第3行失败,但在应用foreach后收集rdd时,它会失败并抛出一个错误

文件"<stdin>",第5行,在<模块> 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())