Iterators & Enumerable

Reviewed & published by Brayan K

Ruby is a dynamic, beginner-friendly programming language, and the Enumerable module gives every collection a shared toolbox — map, select, reduce, and more — for looping and transforming data elegantly.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll transform with map, filter with select, fold with reduce, and chain these methods like a pro.

What You'll Learn in This Lesson

1️⃣ Transform and Filter: map, select, find

map turns a collection into a new one of the same size. select keeps the elements your block approves; reject drops them; find returns the first match. And because each returns a collection, you can chain them into readable pipelines.

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

# map: TRANSFORM every element into a new array (same size).
doubled = numbers.map { |n| n * 2 }
puts doubled.inspect          # -> [2, 4, 6, 8, 10, 12]

# select (alias filter): KEEP only elements where the block is true.
evens = numbers.select { |n| n.even? }
puts evens.inspect            # -> [2, 4, 6]

# reject: the opposite of select.
odds = numbers.reject { |n| n.even? }
puts odds.inspect             # -> [1, 3, 5]

# find (alias detect): the FIRST element matching the block.
first_big = numbers.find { |n| n > 3 }
puts first_big                # -> 4

# Chaining is idiomatic: select THEN map.
result = numbers.select { |n| n.even? }.map { |n| n * 10 }
puts result.inspect           # -> [20, 40, 60]

2️⃣ Aggregate: reduce, predicates, grouping

reduce folds many values into one using an accumulator. Predicate methods like all?, any?, and count answer yes/no/how-many questions, while sort_by and group_by reorganise data.

numbers = [1, 2, 3, 4, 5]

# reduce (alias inject): combine everything into ONE value.
# The block gets the running total (acc) and each element.
total = numbers.reduce(0) { |acc, n| acc + n }
puts total                    # -> 15

# Shorthand: pass a symbol for a simple operator.
puts numbers.reduce(:+)       # -> 15
puts numbers.reduce(1, :*)    # -> 120  (product, starting at 1)

# Other Enumerable favourites:
puts numbers.all? { |n| n > 0 }   # -> true   (every element passes?)
puts numbers.any? { |n| n > 4 }   # -> true   (at least one passes?)
puts numbers.count { |n| n.odd? } # -> 3      (how many pass?)
puts numbers.min_by { |n| -n }    # -> 5      (max via min_by trick)
puts numbers.sort_by { |n| -n }.inspect  # -> [5, 4, 3, 2, 1]

# group elements by a rule:
puts numbers.group_by { |n| n.even? ? :even : :odd }.inspect
# -> {:odd=>[1, 3, 5], :even=>[2, 4]}

Your turn. Process a list of people (hashes) using select and map. Complete the two TODO blocks, then run it.

# 🎯 YOUR TURN — replace each TODO, then run with: ruby people.rb

people = [
  { name: "Ada",  age: 36 },
  { name: "Bo",   age: 17 },
  { name: "Cy",   age: 42 },
  { name: "Di",   age: 15 }
]

# 1) Keep only the adults (age >= 18) with select
adults = people.select { |p| p[:age] >= 18 }   # 👉 TODO: complete the test

# 2) Get just their names with map
names = adults.map { |p| p[:name] }            # 👉 TODO: pull the :name

# 3) Find the average age of EVERYONE
avg = people.map { |p| p[:age] }.sum.to_f / people.length

puts "Adults: #{names.inspect}"
puts "Average age: #{avg.round(1)}"

# ✅ Expected output:
#    Adults: ["Ada", "Cy"]
#    Average age: 27.5

Mini-Challenge: A Sales Report

Filter, total, and format a list of sales by chaining Enumerable methods. Run with ruby sales.rb.

# 🎯 MINI-CHALLENGE: a sales report.
# Save as sales.rb and run with: ruby sales.rb
#
# Given: sales = [120, 340, 90, 560, 200]
# 1. Use select to keep sales >= 200.
# 2. Use reduce (or sum) to total the big sales.
# 3. Use map to add a "$" prefix to each big sale (turn into strings).
# 4. Print the big sales (with $) and their total.
#
# ✅ Example output:
#    Big sales: ["$340", "$560", "$200"]
#    Total: 1100

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Enumerable

ConceptRuby Syntax
Transformarr.map { |x| x*2 }
Filterarr.select { |x| ... }
First matcharr.find { |x| ... }
Foldarr.reduce(:+)
Any / allarr.any? / arr.all?
Grouparr.group_by { }

🎉 Lesson Complete!

Practice quiz

What does `[1, 2, 3].map { |n| n * 2 }` return?

  • 6
  • [1, 2, 3]
  • [2, 4, 6]
  • 12

Answer: [2, 4, 6]. map transforms each element, returning a new array of the same size: [2, 4, 6].

What does `[1, 2, 3, 4].select { |n| n.even? }` return?

  • [2, 4]
  • [1, 3]
  • 2
  • [1, 2, 3, 4]

Answer: [2, 4]. select keeps elements where the block is true — the even numbers [2, 4].

How does reject differ from select?

  • It is identical
  • It returns a single element
  • It sorts the result
  • It keeps elements where the block is FALSE

Answer: It keeps elements where the block is FALSE. reject is the mirror of select: it keeps elements for which the block returns false.

What does `find` (alias detect) return?

  • All matching elements
  • The first matching element (or nil)
  • true or false
  • A count

Answer: The first matching element (or nil). find returns just the first element matching the block, or nil if none match.

What does `[1, 2, 3, 4, 5].reduce(:+)` return?

  • 15
  • 120
  • [1,2,3,4,5]
  • 5

Answer: 15. reduce(:+) folds the collection into one value by summing: 15.

Which method returns true only if EVERY element passes the block?

  • any?
  • count
  • all?
  • find

Answer: all?. all? returns true only when every element satisfies the block; any? needs just one.

What does `numbers.select { |n| n.even? }.map { |n| n * 10 }` demonstrate?

  • A syntax error
  • Chaining Enumerable methods
  • Reducing to one value
  • Sorting

Answer: Chaining Enumerable methods. Because each method returns a collection, you can chain select then map into a pipeline.

If your map block ends in `puts`, what do the mapped values become?

  • The printed strings
  • true
  • An error
  • nil for every element

Answer: nil for every element. puts returns nil, so a block ending in puts maps every element to nil. End the block with the value.

What is the Enumerable module?

  • A class for numbers only
  • A mixin giving collection methods to any class defining each
  • A gem you install
  • A type of loop

Answer: A mixin giving collection methods to any class defining each. Enumerable is a mixin that provides map, select, reduce, etc. to any class that defines each.

What does `numbers.map(&:upcase)` use as shorthand?

  • A range
  • A ternary
  • Symbol-to-proc for { |n| n.upcase }
  • A lambda literal

Answer: Symbol-to-proc for { |n| n.upcase }. &:upcase is the symbol-to-proc shorthand for { |n| n.upcase }.

Continue this course

Frequently asked questions

What's the difference between each and map?

each runs your block once per element purely for the side effect — printing, saving, updating something — and returns the original collection unchanged. map runs your block once per element and collects each block's return value into a brand-new array of the same size. So use each when you just want to do something for every item, and map when you want to transform a collection into a new one. A telltale sign you wanted map: you created an empty array and pushed into it inside an each.

When should I use select, reject, and find?

select keeps every element for which the block returns true, giving you a filtered array (filter is an alias). reject is its mirror image, keeping the elements where the block is false. find (also called detect) returns just the first matching element, or nil if none match — it stops as soon as it finds one, so it's efficient for 'does any item like this exist?' lookups. Reach for select/reject when you want many results and find when you want one.

How does reduce (inject) work?

reduce folds a whole collection into a single value. It keeps an accumulator and runs your block for each element, passing the running accumulator and the current element; whatever the block returns becomes the next accumulator. [1,2,3].reduce(0) { |sum, n| sum + n } walks 0+1, then 1+2, then 3+3 to give 6. You can give it a starting value and, for simple operators, a shorthand symbol: [1,2,3].reduce(:+). It's the Swiss-army knife behind sum, product, and many custom aggregations.

What is the Enumerable module?

Enumerable is a mixin module that provides dozens of collection methods — map, select, reduce, all?, group_by, sort_by, and more — to any class that defines an each method. Both Array and Hash include it, which is why they share the same rich vocabulary. The big idea is that once you learn these methods, they work the same way on every enumerable thing, and you can even make your own classes enumerable by including the module and defining each.