What Does the "Map" Method Do in Ruby?

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
2

8 Answers

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
10

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:

  1. 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]
    
  2. 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
7

For anyone who needs to visualize it:

Here's the full story:

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}

0..param_count means "up to and including param_count". 0...param_count means "up to, but not including param_count".

Range#map does not return an Enumerable, it actually maps it to an array. It's the same as Range#to_a.

It "maps" a function to each item in an Enumerable - in this case, a range. So it would call the block passed once for every integer from 0 to param_count (exclusive - you're right about the dots) and return an array containing each return value.

Here's the documentation for Enumerable#map. It also has an alias, collect.

3

#each

#each runs a function for each element in an array. The following two code excerpts are equivalent:

x = 10
["zero", "one", "two"].each{|element|
    x++
    puts element
}
x = 10
array = ["zero", "one", "two"]

for i in 0..2
    x++
    puts array[i]
end

#map

#map applies a function to each element of an array, returning the resulting array. The following are equivalent:

array = ["zero", "one", "two"]
newArray = array.map{|element| element.capitalize()}
array = ["zero", "one", "two"]

newArray = []
array.each{|element|
    newArray << element.capitalize()
}

#map!

#map! is like #map, but modifies the array in place. The following are equivalent:

array = ["zero", "one", "two"]
array.map!{|element| element.capitalize()}
array = ["zero", "one", "two"]
array = array.map{|element| element.capitalize()}

Map is a part of the enumerable module. Very similar to "collect" For Example:

  Class Car

    attr_accessor :name, :model, :year

    Def initialize (make, model, year)
      @make, @model, @year = make, model, year
    end

  end

  list = []
  list << Car.new("Honda", "Accord", 2016)
  list << Car.new("Toyota", "Camry", 2015)
  list << Car.new("Nissan", "Altima", 2014)

  p list.map {|p| p.model}

Map provides values iterating through an array that are returned by the block parameters.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Chloe Bennett
Author

Chloe Bennett

Chloe Bennett explores the intersection of pop culture, streaming entertainment, digital trends, and contemporary lifestyle. Her weekly commentary reaches thousands of culture enthusiasts.