Hashes in Ruby are collections of key-value pairs, similar to dictionaries in other programming languages.
They allow you to store and retrieve data efficiently using keys.
What You’ll Learn
Table of Contents
1. What Are Hashes?
A hash is a collection of unique keys and their associated values. Keys can be any object (most commonly symbols or strings), and values can be any object.
Example
hash = { name: "Alice", age: 25, city: "New York" }
2. Creating Hashes
2.1 Using Curly Braces
hash = { name: "Bob", age: 30 }
puts hash # Output: {:name=>"Bob", :age=>30}
2.2 Using the Hash Class
hash = Hash.new
hash[:name] = "Charlie"
puts hash # Output: {:name=>"Charlie"}
2.3 Default Value
You can specify a default value for missing keys.
hash = Hash.new("Not Found")
puts hash[:missing_key] # Output: Not Found
3. Accessing Hash Elements
Access Using Keys
person = { name: "Alice", age: 25 }
puts person[:name] # Output: Alice
puts person[:age] # Output: 25
Using fetch for Default Values
person = { name: "Alice" }
puts person.fetch(:age, "Unknown") # Output: Unknown
4. Adding and Updating Elements
Adding New Key-Value Pairs
person = { name: "Alice" }
person[:age] = 25
puts person # Output: {:name=>"Alice", :age=>25}
Updating Existing Keys
person[:name] = "Bob"
puts person # Output: {:name=>"Bob", :age=>25}
5. Deleting Elements
Using delete
person = { name: "Alice", age: 25 }
person.delete(:age)
puts person # Output: {:name=>"Alice"}
6. Iterating Over Hashes
Iterate Through Keys and Values
person = { name: "Alice", age: 25 }
person.each do |key, value|
puts "#{key}: #{value}"
end
# Output:
# name: Alice
# age: 25
Iterate Through Keys Only
person.each_key { |key| puts key }
# Output:
# name
# age
Iterate Through Values Only
person.each_value { |value| puts value }
# Output:
# Alice
# 25
7. Common Hash Methods
7.1 Check for a Key or Value
person = { name: "Alice", age: 25 }
puts person.key?(:name) # Output: true
puts person.value?(25) # Output: true
7.2 Merge Two Hashes
hash1 = { name: "Alice", age: 25 }
hash2 = { city: "New York", age: 30 }
merged = hash1.merge(hash2)
puts merged # Output: {:name=>"Alice", :age=>30, :city=>"New York"}
7.3 Select Specific Elements
person = { name: "Alice", age: 25, city: "New York" }
adults = person.select { |key, value| key == :age && value >= 18 }
puts adults # Output: {:age=>25}
7.4 Reject Specific Elements
person = { name: "Alice", age: 25, city: "New York" }
filtered = person.reject { |key, value| key == :city }
puts filtered # Output: {:name=>"Alice", :age=>25}
7.5 Convert to Array
person = { name: "Alice", age: 25 }
puts person.to_a # Output: [[:name, "Alice"], [:age, 25]]
7.6 Get Keys or Values
person = { name: "Alice", age: 25 }
puts person.keys # Output: [:name, :age]
puts person.values # Output: ["Alice", 25]
8. Practical Examples
8.1 Counting Word Frequencies
text = "hello world hello Ruby"
words = text.split
frequencies = Hash.new(0)
words.each { |word| frequencies[word] += 1 }
puts frequencies
# Output: {"hello"=>2, "world"=>1, "Ruby"=>1}
8.2 Grouping by Criteria
people = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 17 },
{ name: "Carol", age: 30 }
]
grouped = people.group_by { |person| person[:age] >= 18 ? :adult : :minor }
puts grouped
# Output: {:adult=>[{:name=>"Alice", :age=>25}, {:name=>"Carol", :age=>30}], :minor=>[{:name=>"Bob", :age=>17}]}
8.3 Using Hash for Default Configurations
def configure(settings = {})
defaults = { theme: "light", language: "en", notifications: true }
config = defaults.merge(settings)
puts config
end
configure(language: "fr", notifications: false)
# Output: {:theme=>"light", :language=>"fr", :notifications=>false}
8.4 Sorting a Hash by Key or Value
person = { name: "Alice", age: 25, city: "New York" }
# Sort by keys
sorted_by_key = person.sort.to_h
puts sorted_by_key # Output: {:age=>25, :city=>"New York", :name=>"Alice"}
# Sort by values
sorted_by_value = person.sort_by { |key, value| value }.to_h
puts sorted_by_value # Output: {:name=>"Alice", :city=>"New York", :age=>25}
8.5 Hash with Default Values for Caching
cache = Hash.new { |hash, key| hash[key] = key ** 2 }
puts cache[2] # Output: 4
puts cache[3] # Output: 9
puts cache # Output: {2=>4, 3=>9}
9. Best Practices for Using Hashes
- Use Symbols for Keys: Symbols are more memory-efficient and faster than strings as keys.
- Use Default Values: Set default values to handle missing keys gracefully.
- Merge Hashes for Configurations: Use merge to combine default and custom configurations.
- Leverage Iterators: Use each, select, and reject for concise and readable hash operations.
10. Summary
Key Concepts
- Hashes store key-value pairs.
- Access values using keys or methods like fetch.
- Use select, reject, and merge to manipulate hash data.
- Iterating over hashes is straightforward with each, each_key, and each_value.
Examples in Context
Hashes are versatile and powerful for organizing data in Ruby.