Ruby's map | collect methods explained visually 🎨
There's no way around the map
method. Coming from functional programming it's an inevitable part of any developer's everyday life.
Here's an attempt to break it down visually.
Map or Collect?
.map
and .collect
are aliases, which means they go hand in hand together, doing the exact same thing. No one was ever able to measure the meaningfulness of aliases, but here we are, still alive.
".map() and .collect() do the exact same thing."
How it really works
When you call .map()
on a collection, a little gnome with a big finger goes through every element (like in a for-loop) and maps this element to a new element in a new array.
In Ruby, you pass a block to the map
method. This block defines what happens to every element from the collection.
In the example above the "collection" is an array, so for every number inside the array, something happens to the number (a transformation operation). Eventually, the transformation is mapped as a new value in a new array at the exact same position as it was in the original array.
In the end, you see that the map
method returns a brand new array with the new elements inside.
If you've internalized this example, you've got the gist of it. Just to reiterate a bit on your understanding, though:
This is an absolutely useless operation. You have just robbed the map
method of its only purpose: to transform data. You have your original array back, exactly as you passed it. The little gnome was bored, almost to death. You could do something similarly boring if you'd like to finish him:
Here you have an array back with new elements but you haven't used the original elements at all. What a waste.
However useless it may be, at this point you may internalize that everything that the block returns on every iteration, ends up inside the new collection. With map
, the one certain thing is that a new array will be returned. And that's already the biggest difference with Ruby's .each()
method. The each
method also loops through every element of the collection but it doesn't collect all the elements inside a new array in the end (here we go, maybe collect
is not that much of a useless name for the alias after all).
Even if you run map
on a Set, you will get an array in return:
"With .map(), the one thing that's certain is that a new array will be returned."
Even when you do as crazy of a thing as .map!
bang. It still returns a collection. But now our little gnome also takes the transformed values and replaces the original collection's values on every iteration.
So, if you try to assign your map!
bang result additionally to a variable, you'll end up with your original collection's values replaced by the new ones and the newly returned collection inside the variable.
By the way, you will get the same type of collection inside your variable as the collection on which you ran .map!
. For example, if you run map!
on a Ruby Set you'll get a set in return and your original Set gets mutated:
And last but not least, some Ruby magic 🔮
You pick the method that's available on the object in the collection and put it after &:
, a magical key to the world of shortness and conciseness. There's no shorter way to transform values into a new collection. A shorthand that's embraced by Rubyists all over the world. Not only in gnome-land.