The Enumerable Module
Enumerable is one of Ruby's most powerful modules. When you define a single method called each, you automatically get access to dozens of methods: map, select, reject, sort, min, max, and many more. This is the magic of Ruby's design โ define one thing, get everything.
class WordCollection
include Enumerable
def initialize(words)
@words = words
end
def each(&block)
@words.each(&block)
end
end
words = WordCollection.new(["apple", "banana", "cherry", "date"])
# All these work automatically:
puts words.map(&:length).inspect # => [5, 6, 6, 4]
puts words.select { |w| w.start_with?("b") }.inspect # => ["banana"]
puts words.sort.inspect # => ["apple", "banana", "cherry", "date"]
puts words.min # => "apple"
puts words.max # => "date"
puts words.any? { |w| w.length > 5 } # => true
puts words.count # => 4
Try it Yourself ->
Enumerable is Everywhere
Array, Hash, and Range all include Enumerable. That's why you can use map on a hash, select on a range, and sort on an array. They all define each, which gives them everything.
# Array includes Enumerable
puts [3, 1, 2].sort.inspect # => [1, 2, 3]
puts [1, 2, 3, 4].select(&:even?).inspect # => [2, 4]
# Hash includes Enumerable
hash = { a: 1, b: 2, c: 3 }
puts hash.map { |k, v| "#{k}=#{v}" }.inspect
# => ["a=1", "b=2", "c=3"]
# Range includes Enumerable
puts (1..10).select(&:odd?).inspect # => [1, 3, 5, 7, 9]
puts (1..5).reduce(:+) # => 15
Try it Yourself ->
Custom Enumerable: Build Your Own
You can create your own Enumerable class. Define each, and you get map, select, sort, min, max, group_by, partition, and dozens more for free. One method, endless possibilities.
class Fibonacci
include Enumerable
def initialize(limit)
@limit = limit
end
def each
a, b = 0, 1
while a <= @limit
yield a
a, b = b, a + b
end
end
end
fib = Fibonacci.new(100)
puts fib.select(&:even?).inspect
# => [0, 2, 8, 34]
puts fib.map { |n| n * 2 }.inspect
# => [0, 2, 2, 6, 10, 16, 26, 42, 68, 110]
puts fib.max # => 89
puts fib.min # => 0
Try it Yourself ->
Enumerable Methods You'll Use
Here are the most commonly used Enumerable methods. Once you internalize these, you'll write Ruby code that reads like English.
data = [5, 3, 8, 1, 9, 2, 7]
# Finding things
puts data.find { |n| n > 6 } # => 8 (first match)
puts data.select { |n| n.odd? }.inspect # => [5, 3, 1, 9, 7]
puts data.reject { |n| n > 5 }.inspect # => [5, 3, 1, 2]
# Aggregating
puts data.reduce(:+) # => 35
puts data.min # => 1
puts data.max # => 9
puts data.sum # => 35
# Transforming
puts data.map { |n| n * 10 }.inspect # => [50, 30, 80, 10, 90, 20, 70]
puts data.sort.inspect # => [1, 2, 3, 5, 7, 8, 9]
puts data.reverse.inspect # => [7, 2, 9, 1, 8, 3, 5]
# Checking
puts data.any? { |n| n > 8 } # => true
puts data.all? { |n| n > 0 } # => true
puts data.none? { |n| n < 0 } # => true
puts data.include?(5) # => true
Try it Yourself ->
The Power of One Method
This is Ruby's philosophy in action. Instead of giving you a hundred methods to implement, Ruby says: just define each, and we'll handle the rest. It's elegant, DRY, and powerful. When you truly understand Enumerable, you understand what makes Ruby special.
class Primes
include Enumerable
def initialize(count)
@count = count
end
def each
n = 2
yielded = 0
while yielded < @count
yield n if prime?(n)
yielded += 1 if prime?(n)
n += 1
end
end
private
def prime?(n)
return false if n < 2
(2..Math.sqrt(n)).none? { |i| n % i == 0 }
end
end
primes = Primes.new(10)
puts primes.inspect # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
puts primes.select { |p| p > 10 }.inspect # => [11, 13, 17, 19, 23, 29]
puts primes.map { |p| p * 2 }.inspect # => [4, 6, 10, 14, 22, 26, 34, 38, 46, 58]
Try it Yourself ->