Enumerable#map

Updated April 1, 2026 · Enumerable
ruby enumerable map transform collect stdlib

What does map do?

map transforms every element in a collection by passing it through a block, and returns a new array containing the results. The original collection is left unchanged.

Think of it as: “take each item, do something to it, and collect the results.”

Unlike each, which iterates purely for side effects and returns the original collection, map collects and returns what the block produces for each element.

Basic Usage

With a block

[1, 2, 3].map { |n| n * 2 }   # => [2, 4, 6]
["hello", "world"].map(&:upcase)  # => ["HELLO", "WORLD"]

Without a block

When called without a block, map returns an Enumerator:

[1, 2, 3].map   # => #<Enumerator: [1, 2, 3]:map>

This allows chaining with other Enumerable methods:

[1, 2, 3, 4, 5].map.with_index { |n, i| [i, n] }
# => [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]]

Practical Examples

Extracting attributes

users = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
  { name: "Carol", age: 35 }
]

users.map { |u| u[:name] }   # => ["Alice", "Bob", "Carol"]
users.map { |u| u[:age] }   # => [30, 25, 35]

Converting types

["1", "2", "3"].map(&:to_i)         # => [1, 2, 3]
[1.5, 2.7, 3.1].map(&:to_i)        # => [1, 2, 3]
[100, 200, 300].map { |n| n.to_s }  # => ["100", "200", "300"]

Transforming hashes

When called on a hash, map yields key-value pairs:

ages = { alice: 30, bob: 25, carol: 35 }

# Returns an array of arrays
ages.map { |name, age| [name, age * 2] }.to_h
# => { alice: 60, bob: 50, carol: 70 }

# Extract just the keys
ages.map { |name, _| name.to_s }  # => ["alice", "bob", "carol"]

Nested mapping

matrix = [[1, 2], [3, 4], [5, 6]]

matrix.map { |row| row.map { |n| n * 10 } }
# => [[10, 20], [30, 40], [50, 60]]

Using with_index

fruits = ["apple", "banana", "cherry"]

fruits.map.with_index { |fruit, i| "#{i + 1}. #{fruit}" }
# => ["1. apple", "2. banana", "3. cherry"]

Symbol to proc shorthand

[1, 2, 3, 4, 5].map(&:succ)    # => [2, 3, 4, 5, 6]
["hello", "world"].map(&:length)  # => [5, 5]

map vs each: The Key Difference

The most common mistake is confusing map with each. They look similar but behave very differently:

MethodReturnsUse case
eachOriginal collection (unchanged)Iterating for side effects
mapNew array of block resultsTransforming elements
numbers = [1, 2, 3]

result = numbers.each { |n| n * 2 }
result  # => [1, 2, 3]  (original, unchanged!)

result = numbers.map { |n| n * 2 }
result  # => [2, 4, 6]  (new array with transformed values)

When to use each

Use each when you want to perform side effects — printing, writing to a file, updating external state:

[1, 2, 3].each { |n| puts n * 2 }
# Output:
# 2
# 4
# 6
# => [1, 2, 3]

When to use map

Use map when you want to derive a new collection from an existing one:

names = ["alice", "bob", "carol"]
names.map(&:capitalize)   # => ["Alice", "Bob", "Carol"]

collect: The Alias

collect is an exact synonym for map in Ruby. They are identical — same implementation, same return type, same behaviour. Use whichever reads more naturally in your context.

[1, 2, 3].map    { |n| n * 2 }   # => [2, 4, 6]
[1, 2, 3].collect { |n| n * 2 }  # => [2, 4, 6]

map is more common in Ruby code because it reads as “transform each element into something.” collect is the historical name from Smalltalk, Ruby’s predecessor in this design.

# Both produce identical results:
numbers.map(&:to_s)
numbers.collect(&:to_s)

Chaining with Other Enumerable Methods

map returns an array, so you can chain it with other Enumerable methods:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  .select(&:even?)
  .map { |n| n * n }
# => [4, 16, 36, 64, 100]

# Filter out nils with compact
["1", "two", "3", nil, "four"].map { |s| s.to_i if s.is_a?(String) }.compact
# => [1, 3, 4]

Common chains

# Select then map (or map then select — order matters!)
[1, 2, 3, 4, 5].select(&:odd?).map { |n| n * 10 }  # => [10, 30, 50]
[1, 2, 3, 4, 5].map { |n| n * 10 }.select(&:even?)  # => [20, 40]

# Map then reduce
[1, 2, 3, 4].map { |n| n * 2 }.reduce(:+)  # => 20

# Map then flatten
[[1, 2], [3, 4]].map { |arr| arr.map { |n| n + 1 } }
# => [[2, 3], [4, 5]]

Using flat_map

flat_map combines map and flatten in one pass:

[[1, 2], [3, 4]].map { |arr| arr.map { |n| n * 2 } }
# => [[2, 4], [6, 8]]  (array of arrays)

[[1, 2], [3, 4]].flat_map { |arr| arr.map { |n| n * 2 } }
# => [2, 4, 6, 8]  (flattened)

Performance Considerations

map has O(n) time complexity — it visits each element exactly once. It always processes the full collection and creates a new array of the same size.

Memory usage

map creates and returns a new array. For very large collections, this can be significant. If you only need to iterate once (e.g., printing), use each.

# Memory: creates a full new array
squares = (1..1_000_000).map { |n| n**2 }  # lots of memory

# If you just need to print squares:
(1..1_000_000).each { |n| puts n**2 }       # no extra array created

Lazy evaluation with lazy.map

For large or infinite collections, use lazy to defer evaluation:

# Eager: processes all immediately
(1..10).map { |n| n * 2 }.first(3)  # => [2, 4, 6]
# (actually computes all, then takes first 3)

# Lazy: processes only what's needed
(1..Float::INFINITY).lazy.map { |n| n * 2 }.first(3)
# => [2, 4, 6]
# (stops after producing 3 results)

Hash Considerations

When map is called on a hash, it yields [key, value] pairs:

scores = { alice: 100, bob: 85, carol: 92 }

# By default, returns an array of two-element arrays
scores.map { |name, score| "#{name}: #{score}" }
# => ["alice: 100", "bob: 85", "carol: 92"]

# To get a hash back, convert with `to_h`
scores.map { |name, score| [name, score + 10] }.to_h
# => { alice: 110, bob: 95, carol: 102 }

Summary

  • map transforms each element and returns a new array
  • collect is an exact alias — use whichever reads better
  • each returns the original; map returns transformed results
  • Without a block, map returns an Enumerator (lazy by default when chained)
  • map always returns an array, even on hashes (use to_h if you need a hash back)

See Also