Collections
## Learning Objectives
- Work with arrays and their methods
- Master hashes and symbol keys
- Understand ranges
- Use the Enumerable module
## Arrays
### Creating Arrays
```ruby
empty = []
numbers = [1, 2, 3, 4, 5]
mixed = [1, "two", 3.0, nil]
nested = [[1, 2], [3, 4]]
# Array.new
zeros = Array.new(5, 0) # [0, 0, 0, 0, 0]
counted = Array.new(5) { |i| i + 1 } # [1, 2, 3, 4, 5]
```
### Accessing Elements
```ruby
fruits = ["apple", "banana", "cherry", "date"]
puts fruits[0] # "apple"
puts fruits[-1] # "date" (last element)
puts fruits[1, 2] # ["banana", "cherry"] (start, length)
puts fruits[0..2] # ["apple", "banana", "cherry"] (range)
puts fruits.first # "apple"
puts fruits.last # "date"
puts fruits.sample # Random element
```
### Modifying Arrays
```ruby
fruits = ["apple", "banana"]
fruits << "cherry" # Append
fruits.push("date") # Push to end
fruits.unshift("apricot") # Prepend
removed = fruits.pop # Remove and return last
first = fruits.shift # Remove and return first
fruits.insert(1, "blueberry") # Insert at index
fruits.delete("banana") # Remove all occurrences
fruits.delete_at(0) # Remove at index
fruits.reverse!
fruits.sort!
fruits.uniq! # Remove duplicates
```
### Array Methods
```ruby
numbers = [1, 2, 3, 4, 5]
numbers.length # 5
numbers.size # 5
numbers.empty? # false
numbers.include?(3) # true
numbers.join # "12345"
numbers.join(", ") # "1, 2, 3, 4, 5"
numbers.flatten # Flatten nested arrays
numbers.compact # Remove nil values
numbers.shuffle # Random order
numbers.rotate # Rotate elements
```
### Array Searching
```ruby
numbers = [1, 2, 3, 4, 5, 3]
numbers.index(3) # 2 (first index)
numbers.rindex(3) # 5 (last index)
numbers.find { |n| n > 3 } # 4
numbers.select { |n| n > 3 } # [4, 5]
numbers.reject { |n| n > 3 } # [1, 2, 3, 3]
numbers.bsearch { |n| n > 3 } # 4 (binary search)
```
## Hashes
### Creating Hashes
```ruby
empty = {}
user = { "name" => "Alice", "age" => 30 }
# Symbol keys (preferred)
user = { name: "Alice", age: 30 }
user = { :name => "Alice", :age => 30 }
# Hash.new with default
counts = Hash.new(0)
counts[: apples] += 1 # {:apples => 1}
# Block form
defaults = Hash.new { |hash, key| hash[key] = [] }
```
### Hash Accessing Elements
```ruby
user = { name: "Alice", age: 30, city: "NYC" }
puts user[:name] # "Alice"
puts user["name"] # nil (different key type)
puts user[:height] # nil
# Fetch with default
puts user.fetch(:age, 0) # 30
puts user.fetch(:height, 0) # 0
# With block for missing key
puts user.fetch(:height) { 0 } # 0
```
### Modifying Hashes
```ruby
user = { name: "Alice", age: 30 }
user[:city] = "NYC" # Add/update
user.store(:country, "USA")
user.delete(:age) # Remove key
user.delete_if { |k, v| v.nil? }
user.merge!(other_hash) # Merge in place
```
### Hash Methods
```ruby
user = { name: "Alice", age: 30 }
user.keys # [:name, :age]
user.values # ["Alice", 30]
user.to_a # [[:name, "Alice"], [:age, 30]]
user.has_key?(:name) # true
user.key?(:name) # true (alias)
user.value?("Alice") # true
user.has_value?("Alice") # true
user.empty? # false
user.size # 2
```
### Iterating Over Hashes
```ruby
user = { name: "Alice", age: 30, city: "NYC" }
user.each do |key, value|
puts "#{key}: #{value}"
end
user.each_key { |key| puts key }
user.each_value { |value| puts value }
# Transform
Hash[user.map { |k, v| [k, v.to_s] }]
```
## Ranges
### Creating Ranges
```ruby
inclusive = 1..10 # Includes end
exclusive = 1...10 # Excludes end
letters = "a".."z"
alphabet = "a"...("z".ord.chr) rescue "a".."z"
```
### Range Methods
```ruby
range = 1..10
range.to_a # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range.include?(5) # true
range.member?(5) # true (alias)
range.cover?(5) # true (faster than include?)
(1..5).each { |n| puts n }
# Size/Length
(1..10).size # 10
```
## Enumerable Module
Arrays and hashes include Enumerable, providing powerful iteration methods.
### map (collect)
```ruby
[1, 2, 3].map { |n| n * 2 } # [2, 4, 6]
# With symbol
["alice", "bob"].map(&:upcase) # ["ALICE", "BOB"]
```
### select (find_all)
```ruby
[1, 2, 3, 4, 5].select(&:odd?) # [1, 3, 5]
[1, 2, 3, 4, 5].find_all { |n| n > 2 } # [3, 4, 5]
```
### reject
```ruby
[1, 2, 3, 4, 5].reject(&:even?) # [1, 3, 5]
```
### reduce (inject)
```ruby
[1, 2, 3, 4, 5].reduce(0) { |sum, n| sum + n } # 15
[1, 2, 3, 4, 5].reduce(:+) # 15 (shorthand)
# With initial value omitted
[1, 2, 3].reduce(:*) # 6
```
### find (detect)
```ruby
[1, 2, 3, 4, 5].find { |n| n > 2 } # 3
[1, 2, 3, 4, 5].detect { |n| n > 2 } # 3
```
### count
```ruby
[1, 2, 3, 4, 5].count # 5
[1, 2, 3, 4, 5].count(&:even?) # 2
```
### sort and sort_by
```ruby
[3, 1, 4, 1, 5, 9, 2, 6].sort # [1, 1, 2, 3, 4, 5, 6, 9]
users = [{name: "Bob", age: 30}, {name: "Alice", age: 25}]
users.sort_by { |u| u[:age] } # Sorted by age
```
### group_by
```ruby
[1, 2, 3, 4, 5, 6].group_by(&:odd?)
# {true=>[1, 3, 5], false=>[2, 4, 6]}
```
### partition
```ruby
scores = [45, 70, 85, 90, 55]
pass, fail = scores.partition { |s| s >= 60 }
# pass = [70, 85, 90]
# fail = [45, 55]
```
### zip
```ruby
[1, 2, 3].zip([4, 5, 6]) # [[1, 4], [2, 5], [3, 6]]
```
### take and drop
```ruby
[1, 2, 3, 4, 5].take(3) # [1, 2, 3]
[1, 2, 3, 4, 5].drop(2) # [3, 4, 5]
```
## Sets
```ruby
require 'set'
s1 = Set.new([1, 2, 3])
s2 = Set.new([2, 3, 4])
s1.union(s2) # Set#{1, 2, 3, 4}
s1.intersection(s2) # Set#{2, 3}
s1.difference(s2) # Set#{1}
```
## Summary
- Arrays: ordered, integer-indexed collections
- Hashes: key-value pairs, symbol keys preferred
- Ranges: sequential data with `..` (inclusive) or `...` (exclusive)
- Enumerable: module providing powerful iteration methods
- `map`: transform elements
- `select/reject`: filter elements
- `reduce`: combine elements
- `find`: get first match
- `sort_by`: sort by property
- `group_by`: group by criteria
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →