Enumerably yours
The wide world of Ruby seems like an unchartable labyrinth of complicated looping spaghetti. But upon closer examination it has some straight-forward built in methods that simpify seemingly impossible tasks. One such method is map. Map is a method that operates on an array by iterating over each element and performing some declared code on each item. This may seem similar to the method called each, and it is, but not identical. Each will iterate over an array and perform the requested code while looping and when finished, it will leave the array in the same state that it found it. With map it will perform the code and push the elements that the code requests into a temporary new array that exists only while the map process is running. If we ask for my_array at the end, we will will see the original array, but not the temporary mapped array. This is because Ruby automatically returns the last process in the stack, and only displays other things when requested. It works something like this:
my_array = [1, 2, 3, 4, 5, 6, 7]
my_array.map {|x| if x % 2 == 0
x * 10
end}
my_array
---
=> [1, 2, 3, 4, 5, 6, 7]
This is a good demonstration of how the original array remains unaltered, but not a good demonstration of what is happening during the mapping process. To see map in action, we will ask Ruby to print the mapping to the console by putting a p in front of the map call.
my_array = [1, 2, 3, 4, 5, 6, 7]
p my_array.map {|x| if x % 2 == 0
x * 10
end}
my_array
---
[nil, 20, nil, 40, nil, 60, nil]
=> [1, 2, 3, 4, 5, 6, 7]
And there we have it. Or do we? As you can see the numbers that are even (divisible by 2) get the code block run on them; that is, they are multiplied by ten. The odd numbers, however, are not so lucky. They get wiped off the return array completely and replaced by nil. This is the cruel, cold, uncaring nature of map. It wants so badly to do something to the index of an array that if it encounters something that it can't iterate on, it obliterates it. But odd numbers don't deserve such treatment. In order to return the odd numbers unchanged into the mapped array, we need to give map something to do with them. In this case we can simply tell map that if a number is not even, to simply return that number back.
my_array = [1, 2, 3, 4, 5, 6, 7]
p my_array.map {|x| if x % 2 == 0
x * 10
else x
end}
my_array
---
[1, 20, 3, 40, 5, 60, 7]
=> [1, 2, 3, 4, 5, 6, 7]
This is useful if you want to map new information from an existing array, but what if you want to run code on the original array to alter it permanently? This is still possible with map, but we then need to use the destructive form with an exclamation point (or bang) on the end - map! The destructive form means that the original array has been altered and now holds new information. I know that destructive is a rather violent term for software, but that's all it means.
my_array = [1, 2, 3, 4, 5, 6, 7]
p my_array.map! {|x| if x % 2 == 0
x * 10
else x
end}
my_array
---
[1, 20, 3, 40, 5, 60, 7]
=> [1, 20, 3, 40, 5, 60, 7]
And that's it! As you can see when we requested to see my_array, it is now permanently changed to reflect the mapping process. Map is one of the most useful and versatile tools in the Rubyists toolkit, so it's a good idea to become well acquainted!