I am having trouble understanding the differences between map
and each
, and where and when to use them.
I read \"What does map do?\" and \
The difference is that each
is performing an action on each element in the array, returning the original array. The action performed possibly mutated the element.
Whereas map
is performing an action on each element in the array and returning its result as an array.
The map
method takes an enum
given some block, and iterates through it doing some logic. In your case the logic is x+1
. As you say it will not mutate anything unless you use !
.
each
is simply returning the array that is being called.
Let's take an example of:
names = ["bob"]
If we do:
names.each{|names| names + "somestring"}
the output is still ["bob"]
. The reason your second example is different is due to the puts
.
As an exercise try doing:
y = [1,2,3].each {|x| puts x + 1}
You will get:
2
3
4
[1,2,3]
tl;dr: I use map
if I want to change my collection, apply a transformation on it, end up with something different. I use each
if I just need to visit every element in a collection.
Key point is: you should use map
if you want to apply a transformation on an array (an enumerable in reality, but let's keep it simple at the beginning). Otherwise, if you don't need to change your array, you can simply use each
.
Note that in the code below you are not mutating the array but you are simply take advantage of the local string to print each string with a suffix.
names = ['danil', 'edmund']
names.each { |name| puts name + ' is a programmer' }
Obviously, you could do the same with map
but in this case you don't need it and you have to use an each too to print every element. The code would be
names = ['danil', 'edmund']
names.map! { |name| name + ' is a programmer' }
# or names = names.map { |name| name + ' is a programmer' }
name.each { |name| puts name }
In the first case, map
:
z = [1,2,3].map {|x| x + 1}
will take each element in the given array and perform the operation in the block and return a new array, so here it returns [2,3,4]
.
.each
executes the block for each of the elements in the array, and it will not change anything in the array, so here it performs x + 1
, but it doesn't store it anywhere, hence in the second case it just returns the array.
Now in the third example you posted, you are printing output in the block itself. Again, there is no change in the array itself.
This is covered in Ruby's documentation in multiple places but the easiest to understand for your use is in the Array documentation for each:
each { |item| block } → ary
each → Enumerator
Calls the given block once for each element in self, passing that element as a parameter. Returns the array itself.
If no block is given, an Enumerator is returned.
a = [ "a", "b", "c" ] a.each {|x| print x, " -- " }
produces:
a -- b -- c --
Note that it says "Returns the array itself."
Compare that to map:
map { |item| block } → new_ary
map → Enumerator
Invokes the given block once for each element of self.
Creates a new array containing the values returned by the block.
See also Enumerable#collect.
If no block is given, an Enumerator is returned instead.
a = [ "a", "b", "c", "d" ] a.collect { |x| x + "!" } #=> ["a!", "b!", "c!", "d!"] a.map.with_index { |x, i| x * i } #=> ["", "b", "cc", "ffffd"] a #=> ["a", "b", "c", "d"]
Note that it says "Creates a new array containing the values returned by the block."
This example should help knowing the above:
foo = [1,2,3]
foo.each { |i| puts i + 1 } # => [1, 2, 3]
foo.map { |i| i + 1 } # => [2, 3, 4]
# >> 2
# >> 3
# >> 4
where # =>
is the return value of the block and # >>
is the captured STDOUT from puts
.
And, knowing all that, use each
when you want to display elements in the array or extract and reuse those elements as parameters or to build things. Use map
when you want to change the elements of the array into something else.