Is there a difference between foreach and map?
Ok this is more of a computer science question, than a question based on a particular language, but is there a difference between a map operation and a foreach operation? Or are they simply different names for the same thing?
Different.
foreach iterates over a list and performs some operation with side effects to each list member (such as saving each one to the database for example)
map iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (such as converting a list of strings to uppercase)
The important difference between them is that map
accumulates all of the results into a collection, whereas foreach
returns nothing. map
is usually used when you want to transform a collection of elements with a function, whereas foreach
simply executes an action for each element.
In short, foreach
is for applying an operation on each element of a collection of elements, whereas map
is for transforming one collection into another.
There are two significant differences between foreach
and 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. Allforeach
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. Themap
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, themap
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.protototype.map
method & Array.protototype.forEach
are both quite similar.
Run the following code: 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));
});
They give the exact ditto result.
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
But the twist comes when you run the following code:-
Here I've simply assigned the result of the return value from the map and forEach methods.
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();
Now the result is something tricky!
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
Conclusion
Array.prototype.map
returns an array but Array.prototype.forEach
doesn't. So you can manipulate the returned array inside the callback function passed to the map method and then return it.
Array.prototype.forEach
only walks through the given array so you can do your stuff while walking the array.
the most 'visible' difference is that map accumulates the result in a new collection, while foreach is done only for the execution itself.
but there are a couple of extra assumptions: since the 'purpose' of map is the new list of values, it doesn't really matters the order of execution. in fact, some execution environments generate parallel code, or even introduce some memoizing to avoid calling for repeated values, or lazyness, to avoid calling some at all.
foreach, on the other hand, is called specifically for the side effects; therefore the order is important, and usually can't be parallelised.