What does the "map" method do in Ruby?
I'm new to programming. Can someone explain what .map
would do in:
params = (0...param_count).map
Solution 1:
The map
method takes an enumerable object and a block, and runs the block for each element, outputting each returned value from the block (the original object is unchanged unless you use map!)
:
[1, 2, 3].map { |n| n * n } #=> [1, 4, 9]
Array
and Range
are enumerable types. map
with a block returns an Array. map!
mutates the original array.
Where is this helpful, and what is the difference between map!
and each
? Here is an example:
names = ['danil', 'edmund']
# here we map one array to another, convert each element by some rule
names.map! {|name| name.capitalize } # now names contains ['Danil', 'Edmund']
names.each { |name| puts name + ' is a programmer' } # here we just do something with each element
The output:
Danil is a programmer
Edmund is a programmer
Solution 2:
map
, along with select
and each
is one of Ruby's workhorses in my code.
It allows you to run an operation on each of your array's objects and return them all in the same place. An example would be to increment an array of numbers by one:
[1,2,3].map {|x| x + 1 }
#=> [2,3,4]
If you can run a single method on your array's elements you can do it in a shorthand-style like so:
-
To do this with the above example you'd have to do something like this
class Numeric def plusone self + 1 end end [1,2,3].map(&:plusone) #=> [2,3,4]
-
To more simply use the ampersand shortcut technique, let's use a different example:
["vanessa", "david", "thomas"].map(&:upcase) #=> ["VANESSA", "DAVID", "THOMAS"]
Transforming data in Ruby often involves a cascade of map
operations. Study map
& select
, they are some of the most useful Ruby methods in the primary library. They're just as important as each
.
(map
is also an alias for collect
. Use whatever works best for you conceptually.)
More helpful information:
If the Enumerable object you're running each
or map
on contains a set of Enumerable elements (hashes, arrays), you can declare each of those elements inside your block pipes like so:
[["audi", "black", 2008], ["bmw", "red", 2014]].each do |make, color, year|
puts "make: #{make}, color: #{color}, year: #{year}"
end
# Output:
# make: audi, color: black, year: 2008
# make: bmw, color: red, year: 2014
In the case of a Hash (also an Enumerable
object, a Hash is simply an array of tuples with special instructions for the interpreter). The first "pipe parameter" is the key, the second is the value.
{:make => "audi", :color => "black", :year => 2008}.each do |k,v|
puts "#{k} is #{v}"
end
#make is audi
#color is black
#year is 2008
To answer the actual question:
Assuming that params
is a hash, this would be the best way to map through it: Use two block parameters instead of one to capture the key & value pair for each interpreted tuple in the hash.
params = {"one" => 1, "two" => 2, "three" => 3}
params.each do |k,v|
puts "#{k}=#{v}"
end
# one=1
# two=2
# three=3
Solution 3:
For anyone who needs to visualize it:
Here's the full story:
https://richstone.io/rubys-map-collect-methods-explained-visually/
Solution 4:
Using ruby 2.4 you can do the same thing using transform_values
, this feature extracted from rails to ruby.
h = {a: 1, b: 2, c: 3}
h.transform_values { |v| v * 10 }
#=> {a: 10, b: 20, c: 30}