Collections: Arrays & Hashes
Master Ruby Arrays and Hashes, and the Enumerable module methods (map, select, reduce) that make Ruby collection code so expressive.
Introduction
Arrays and Hashes are Ruby's two core collection types, and both gain enormous power from the Enumerable module — a shared set of methods that makes transforming, filtering, and summarizing collections read almost like a description of what you want, not a step-by-step recipe for how to get it.
- How to build, index, and modify Arrays.
- How to build and use Hashes, including modern symbol-key shorthand syntax.
- What the Enumerable module is, and the map/select/reduce methods it provides.
- How to chain Enumerable methods into clear, readable transformation pipelines.
Arrays
Ruby Arrays are ordered, resizable, zero-indexed lists — familiar if you've used arrays in most other languages (a contrast with Lua's 1-based tables, if you've taken that course too).
fruits = ["apple", "banana", "cherry"]
puts fruits[0] # applefruits.push("date") # same as fruits << "date"puts fruits.length # 4fruits.delete("banana")puts fruits # ["apple", "cherry", "date"]Click Run to see what this code prints.
Hashes
A Hash stores key-value pairs. Modern Ruby style favors Symbol keys with a shorthand syntax that reads almost like named parameters.
player = { name: "Kiran", level: 5, health: 100 }
puts player[:name]player[:level] += 1puts playerClick Run to see what this code prints.
player = { name: "Kiran", ... } is shorthand for { :name => "Kiran", ... } — the older "hash rocket" syntax, which you'll still see in existing codebases and is required for non-symbol keys.
The Enumerable Module
Both Array and Hash include Ruby's built-in Enumerable module (the mixin pattern from lesson 9 in action), which is why the same rich set of transformation methods — map, select, reduce, and dozens more — works consistently across both collection types.
map, select, and reduce
Use case: .map transforms every element and returns a new collection of the results. .select keeps only elements matching a condition. .reduce combines every element into a single accumulated value.
numbers = [1, 2, 3, 4, 5, 6]
doubled = numbers.map { |n| n * 2 }evens = numbers.select { |n| n.even? }total = numbers.reduce(0) { |sum, n| sum + n }
puts doubled.inspectputs evens.inspectputs totalClick Run to see what this code prints.
Chaining Enumerable Methods
Because each Enumerable method typically returns another Array, chaining several together reads as a clear, linear pipeline — a direct extension of the method chaining introduced in lesson 5.
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = numbers.select { |n| n.even? }.map { |n| n * n }.reduce(:+)puts resultClick Run to see what this code prints.
Reading left to right: keep only even numbers (2, 4, 6, 8, 10), square each one (4, 16, 36, 64, 100), then sum them all together with reduce(:+) — a compact, symbol-shorthand way of writing reduce { |a, b| a + b }.
Common Mistakes
- Manually writing a loop with an empty array and .push inside it, when .map already expresses the same transformation more clearly.
- Confusing .select (keeps matching elements) with .reject (keeps non-matching elements) — easy to mix up at a glance.
- Forgetting that most Enumerable methods return a new collection rather than modifying the original in place, unless you use their ! (bang) variant.
Best Practices
- Reach for map/select/reduce over manual loops whenever you're transforming or filtering a collection — it's both more idiomatic and usually more readable.
- Use symbol keys with the modern shorthand ({ key: value }) for Hashes unless you specifically need non-symbol keys.
- Chain Enumerable methods for clear pipelines, but break especially long chains into named intermediate variables if readability starts to suffer.
Frequently Asked Questions
.each runs a block for its side effects and returns the original collection unchanged; .map runs a block and returns a brand new collection built from the block's return values.
Yes — including Enumerable in your own class (and implementing an each method) gives your class access to map, select, reduce, and the rest, exactly like Array and Hash get them.
It's shorthand for reduce { |sum, n| sum + n } — passing a Symbol representing an operator to reduce applies that operation between each pair of elements automatically.
Key Takeaways
- Arrays are ordered, resizable, and zero-indexed.
- Hashes store key-value pairs, with Symbol-key shorthand syntax as the modern default style.
- The Enumerable module gives both Array and Hash a shared, rich set of transformation methods.
- map, select, and reduce cover the vast majority of everyday collection transformations, and chain together cleanly.
Summary
Arrays, Hashes, and Enumerable together are what make Ruby collection code so compact and expressive. Next, you'll cover Gems and Bundler — how Ruby projects manage third-party dependencies.