Hashes in Ruby
Hashes are one of the most versatile and frequently used data structures in Ruby. If you’ve worked with dictionaries in Python or objects in JavaScript, you’ll feel right at home with Ruby hashes.
In this tutorial, you’ll learn what hashes are, how to create them, and how to use them effectively in your Ruby programs.
What is a Hash?
A hash (also called an associative array or dictionary in other languages) is a collection of key-value pairs. Unlike arrays, which use numeric indices, hashes let you access values using custom keys.
# A simple hash representing a user's information
user = {
"name" => "Alice",
"age" => 30,
"city" => "London"
}
Each key maps to a value, and you can retrieve any value instantly using its key—regardless of where it appears in the hash.
Creating Hashes
There are several ways to create a hash in Ruby:
# Using curly braces (most common)
person = { "name" => "Bob", "occupation" => "Developer" }
# Using the Hash.new constructor
scores = Hash.new
# With a default value
zeros = Hash.new(0) # Default value is 0
# Using symbols as keys (recommended for better performance)
config = {
:debug => true,
:timeout => 30
}
# Modern symbol syntax (Ruby 1.9+)
settings = {
theme: "dark",
language: "en"
}
Pro tip: Using symbols as keys is the Ruby convention and offers better memory efficiency than strings.
Accessing Values
Retrieve values from a hash using bracket notation:
user = { name: "Charlie", age: 25, city: "Paris" }
puts user[:name] # => "Charlie"
puts user[:age] # => 25
puts user[:country] # => nil
# Using fetch - raises error if key missing
puts user.fetch(:name) # => "Charlie"
puts user.fetch(:country, "Unknown") # => "Unknown" (with default)
The fetch method is safer when you’re unsure whether a key exists—it lets you provide a default value or handle missing keys explicitly.
Modifying Hashes
Ruby provides many ways to add, update, and remove hash entries:
book = { title: "The Great Gatsby", author: "F. Scott Fitzgerald" }
# Adding new key-value pairs
book[:year] = 1925
book[:pages] = 180
# Updating existing values
book[:author] = "F. Scott Fitzgerald (Updated Edition)"
# Removing keys
book.delete(:pages)
# Clear all entries
# book.clear
Useful Modification Methods
inventory = { apples: 5, bananas: 3, oranges: 8 }
# Merge two hashes (keys from other hash overwrite duplicate keys)
more_fruit = { bananas: 10, grapes: 15 }
inventory.merge!(more_fruit)
puts inventory
# => { apples: 5, bananas: 10, oranges: 8, grapes: 15 }
# Only keep certain keys
user_data = { name: "Diana", email: "diana@example.com", age: 28, city: "NYC" }
user_data.slice!(:name, :email)
# => { name: "Diana", email: "diana@example.com" }
Iterating Over Hashes
One of the most powerful features of hashes is the ability to iterate over key-value pairs:
prices = { coffee: 4, tea: 3, soda: 2 }
# Iterate over each key-value pair
prices.each do |key, value|
puts "#{key}: $#{value}"
end
# Output:
# coffee: $4
# tea: $3
# soda: $2
# Iterate over only keys
prices.each_key { |key| puts key }
# Iterate over only values
prices.each_value { |value| puts value }
# With index
prices.each_with_index do |(key, value), index|
puts "#{index + 1}. #{key} = #{value}"
end
Common Hash Methods
Ruby hashes come with many built-in methods that make common operations trivial:
movie = { title: "Inception", year: 2010, director: "Christopher Nolan" }
# Check if hash has a key
movie.key?(:title) # => true
movie.has_key?(:rating) # => false
# Check if hash has a value
movie.value?("Inception") # => true
# Get all keys or values as arrays
movie.keys # => [:title, :year, :director]
movie.values # => ["Inception", 2010, "Christopher Nolan"]
# Hash size
movie.length # => 3
movie.size # => 3
movie.empty? # => false
# Check if empty
{}.empty? # => true
Practical Examples
Counting Occurrences
Hashes are perfect for counting things:
# Count letter frequency in a string
text = "hello world"
frequency = Hash.new(0)
text.each_char do |char|
frequency[char] += 1
end
puts frequency
# => {"h"=>1, "e"=>1, "l"=>3, "o"=>2, " "=>1, "w"=>1, "r"=>1, "d"=>1}
Grouping Data
# Group people by age
people = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
{ name: "Charlie", age: 30 }
]
grouped = people.group_by { |person| person[:age] }
puts grouped
# => {30=>[{:name=>"Alice", :age=>30}, {:name=>"Charlie", :age=>30}],
# 25=>[{:name=>"Bob", :age=>25}]}
Handling Options
Hashes are commonly used to pass optional parameters to methods:
def create_user(name, options = {})
defaults = { age: 18, role: "user", active: true }
settings = defaults.merge(options)
puts "Creating user: #{name}"
puts " Age: #{settings[:age]}"
puts " Role: #{settings[:role]}"
puts " Active: #{settings[:active]}"
end
create_user("Emma")
create_user("Frank", age: 25, role: "admin")
When to Use Hashes
Use hashes when you need:
- Key-value associations (like a dictionary)
- Fast lookups by custom keys
- Grouping related data together
- Counting or aggregating items
Consider alternatives when you need:
- Ordered sequences → use Arrays
- Unique values only → use Sets
- Numeric indexing → use Arrays
Summary
Hashes are essential in Ruby programming. They provide fast key-based access to data and support powerful operations like merging, filtering, and transforming.
Key takeaways:
- Use symbols as keys for better performance
- Access values with
hash[key]orhash.fetch(key, default) - Iterate with
each,each_key, oreach_value - Use built-in methods like
merge,slice, andgroup_byfor common tasks
Now that you understand hashes, you’re ready to explore Blocks and Iterators—Ruby’s powerful way of passing executable code around.