Arrays and Hashes in Ruby
The two workhorse collection types -- ordered lists and key/value lookups -- and the core methods you'll use daily.
2 min read
Arrays and hashes are the two collections you'll reach for constantly in Ruby. Almost everything else in the Collections section builds on these two.
Arrays: ordered lists
fruits = ["apple", "banana", "cherry"]
fruits[0] # "apple"
fruits[-1] # "cherry" -- negative indexes count from the end
fruits.first # "apple"
fruits.last # "cherry"
fruits.length # 3Arrays are zero-indexed, like most languages, but negative indexing (-1 for the last element) is a genuinely useful Ruby convenience you won't find everywhere.
fruits << "date" # append -- shovel operator, same as fruits.push("date")
fruits.push("elderberry")
fruits.pop # removes and returns the last element
fruits.include?("banana") # true
fruits.sort # new sorted array; sort! sorts in place
fruits.reverseArrays can hold mixed types ([1, "two", :three, [4]]), and slicing works with ranges:
numbers = [10, 20, 30, 40, 50]
numbers[1..3] # [20, 30, 40] -- inclusive range
numbers[1...3] # [20, 30] -- exclusive range (stops before index 3)
numbers[1, 2] # [20, 30] -- start index, lengthHashes: key/value pairs
user = { name: "Ada", role: :admin, age: 36 }
user[:name] # "Ada"
user[:missing] # nil -- no error for a missing key
user.fetch(:name) # "Ada" -- like [], but raises KeyError if missing
user.fetch(:missing, "default") # "default" -- with a fallback[] silently returns nil for a missing key, which is convenient but can hide bugs; fetch is the safer choice when a missing key should be loud rather than silent.
user[:email] = "ada@example.com" # add or update a key
user.key?(:name) # true
user.delete(:age)
user.keys # [:name, :role, :email]
user.values # ["Ada", :admin, "ada@example.com"]Iterating both
["a", "b", "c"].each_with_index do |letter, i|
puts "#{i}: #{letter}"
end
user.each do |key, value|
puts "#{key} => #{value}"
endeach_with_index is the idiomatic way to get both the value and its position without manually tracking a counter.
Converting between them
[[:a, 1], [:b, 2]].to_h # { a: 1, b: 2 }
{ a: 1, b: 2 }.to_a # [[:a, 1], [:b, 2]]This conversion comes up often after using map or select on a hash — those methods work through the hash as an array of [key, value] pairs, so the result often needs .to_h to turn back into a hash.
Nested structures
Real data is rarely flat — a hash of arrays, an array of hashes, is the everyday shape of JSON-like data in Ruby:
users = [
{ name: "Ada", role: :admin },
{ name: "Grace", role: :member },
]
users.each { |u| puts "#{u[:name]} is a #{u[:role]}" }Comfort with this array-of-hashes shape pays off immediately once you start working with real APIs or parsed JSON, both of which land in Ruby as exactly this combination.
Test what you just learned
4 quick questions. Get all of them right to unlock the next lesson.
You can take the quiz without an account — logging in just lets your result count toward your progress.