Ruby Hash Iteration Patterns
Ruby hashes preserve insertion order and play beautifully with the same `Enumerable` methods that work on arrays. This snippet covers the basic `each_pair` walk, transforming with `transform_keys` and `transform_values` (Ruby 2.4+/2.5+), and filtering plus reducing into a new hash. Use these to keep hash transformations as concise as their array counterparts.
1,167 views
11
ages = { ada: 36, linus: 54, margaret: 88 }
ages.each_pair do |name, age|
puts "#{name} is #{age}"
end
# each_key and each_value give one half at a time.
ages.each_key { |k| print k, " " }
puts
ages.each_value { |v| print v, " " }
puts
puts "size=#{ages.size} keys=#{ages.keys.inspect}"each_pair (alias each) yields key/value pairs in insertion order; Ruby has guaranteed hash ordering since 1.9. each_key and each_value are convenience iterators when you need only one side of each entry. keys and values return arrays you can chain further map/select on, but for one-shot loops the each-variants avoid building an intermediate array. Hash iteration order makes hashes a natural drop-in for ordered configuration maps; do not assume the same in Python before 3.7 or Java's HashMap.
config = { 'host' => 'localhost', 'port' => 5432, 'user' => 'ada' }
# Convert all string keys to symbols (a common loading pattern).
sym_config = config.transform_keys(&:to_sym)
p sym_config # {:host=>"localhost", :port=>5432, :user=>"ada"}
# Apply a uniform transform to every value.
shouty = sym_config.transform_values { |v| v.to_s.upcase }
p shouty
# Filtering with select returns a new hash.
strings_only = config.select { |_k, v| v.is_a?(String) }
p strings_onlytransform_keys (Ruby 2.5+) and transform_values (Ruby 2.4+) return a new hash with the keys or values run through the block; the OTHER side stays untouched. The &:to_sym form passes a symbol-as-proc. These are the cleanest replacements for the old Hash[h.map { |k, v| [k.to_sym, v] }] idiom that you will still see in older codebases. select and reject on a hash also return a hash (not an array of pairs), which lets you chain hash transformations end-to-end without breaking out of the type.
scores = { ada: 100, linus: 92, margaret: 99, others: 50 }
# Build a new hash keeping only winners and bumping their score.
bumped = scores.each_with_object({}) do |(name, score), out|
out[name] = score + 5 if score >= 90
end
p bumped
# Equivalent with inject (require returning the hash from the block).
bumped2 = scores.inject({}) do |out, (name, score)|
out[name] = score + 5 if score >= 90
out
end
p bumped2
# Sum of all values:
puts "total=#{scores.values.sum}"each_with_object({}) is the cleanest hash-builder: pass the seed object as the argument, mutate it inside the block, and the method returns it for you. The destructuring (name, score) unpacks the key/value pair without a manual pair[0] / pair[1]. The equivalent with inject requires explicitly returning the accumulator at the end of the block, which is easy to forget; prefer each_with_object for hash and array building. For aggregating values, scores.values.sum (or inject(:+)) is shortest; lean on the right tool for the right shape.
