Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
58: The Enumerable Module Methods: map, select, reduce
Wait, why use map when I can just use each and a new array?
This is the first thing almost every Rubyist asks. You're thinking: "I can just initialize an empty array, loop through my collection with each, and push the transformed values into that array." You're not wrong—it works. But it's verbose and, frankly, not the "Ruby way."
map (also known as collect) is designed specifically for transformation. It says: "Give me this list, and I'll give you a brand new list of the exact same size, but with every element changed according to this block."
orders = [
{ id: 1, total: 25.50 },
{ id: 2, total: 10.00 },
{ id: 3, total: 42.25 }
]
# The "clunky" way
totals = []
orders.each { |o| totals << o[:total] }
# The map way
totals = orders.map { |o| o[:total] }
# => [25.50, 10.00, 42.25]
I always prefer map because it expresses intent. When I see map in a code review, I immediately know the goal is to create a translated version of the original list. When I see each, I assume you're performing a side effect, like saving to a database or printing to a console.
Is select just a filter? And how does it differ from find?
Exactly. select is your go-to for filtering. It returns a new array containing every element for which the block returns true. If nothing matches, you get an empty array.
The confusion usually happens between select and find (or detect). The difference is simple: select gives you everything that matches; find gives you the first thing that matches and then stops looking.
products = [
{ name: "Hammer", category: "Tools", price: 15 },
{ name: "Screwdriver", category: "Tools", price: 8 },
{ name: "Paintbrush", category: "Painting", price: 12 },
{ name: "Roller", category: "Painting", price: 20 }
]
# I want all the tools
tools = products.select { |p| p[:category] == "Tools" }
# => [{name: "Hammer"...}, {name: "Screwdriver"...}]
# I just want the first painting supply I can find
first_paint = products.find { |p| p[:category] == "Painting" }
# => { name: "Paintbrush", category: "Painting", price: 12 }
Pro tip: If you want the opposite of select (everything that doesn't match), Ruby gives you reject. It's much cleaner than writing select { |p| !p[:category] == "Tools" }.
I'm stuck on reduce. What is the "accumulator" actually doing?
reduce (also called inject) is the most powerful of the three, but it's definitely the hardest to wrap your head around. Think of it as "folding" a list down into a single value. Whether that value is a number, a string, or even a hash, it's up to you.
The "accumulator" (usually named sum or memo) is just a variable that carries the result from one iteration to the next. If you provide an initial value, the accumulator starts there. If not, it starts with the first element of the collection.
cart_items = [12.99, 5.00, 22.50, 3.10]
# We start the accumulator at 0.0
grand_total = cart_items.reduce(0.0) do |sum, price|
sum + price
end
# => 43.59
Here is the play-by-play of what's happening inside that block:
- Iteration 1:
sumis 0.0,priceis 12.99. Returns 12.99. - Iteration 2:
sumis now 12.99,priceis 5.00. Returns 17.99. - Iteration 3:
sumis 17.99,priceis 22.50. Returns 40.49. - Iteration 4:
sumis 40.49,priceis 3.10. Returns 43.59.
Once you're comfortable with this, you'll see a shorthand version in professional code: cart_items.reduce(0, :+). It does the exact same thing as the block above, just way more concisely. I suggest mastering the block version first so you actually understand the mechanics.
📋 Practical Task
Exercise: Inventory Value Calculator
You are building a small inventory management tool for a hardware store. You have an array of hashes representing products in the warehouse. Each product has a name, a price, and a quantity.
inventory = [
{ name: "Power Drill", price: 89.99, quantity: 5 },
{ name: "Box of Nails", price: 12.50, quantity: 20 },
{ name: "Work Bench", price: 150.00, quantity: 2 },
{ name: "Safety Goggles", price: 15.00, quantity: 10 },
{ name: "Tape Measure", price: 8.00, quantity: 15 }
]
Your task is to write a script that does the following:
- Use
selectto create a new list calledexpensive_itemscontaining only products with a price greater than $20.00. - Use
mapto create a new list calledstock_valuesthat contains the total value for each item in the original inventory (price multiplied by quantity). - Use
reduceto calculate thetotal_warehouse_valueby summing up all the values in thestock_valuesarray.
Print the expensive_items, the stock_values, and the total_warehouse_value to the console to verify your results.
There are no comments for now.