rubyguides

Hash#to_h

Hash#to_h converts the hash to a plain Hash instance. When called without a block, it returns self for a plain Hash but returns a new Hash for subclasses. With a block, it transforms each key-value pair into whatever you return from the block.

No Block: Regular Hash

For a plain Hash, to_h returns self:

h = { a: 1, b: 2 }
h.to_h
# => { a: 1, b: 2 }
h.to_h.object_id == h.object_id  # true — same object

This isn’t useful for plain hashes, but matters when dealing with subclassed hashes.

Subclassed Hash

If you subclass Hash, to_h returns a plain Hash with the same content:

class CustomHash < Hash
end

ch = CustomHash.new
ch[:a] = 1
ch[:b] = 2

plain = ch.to_h
plain.class  # => Hash (not CustomHash)
plain        # => { a: 1, b: 2 }

This is the correct behavior for converting subclassed hashes to regular hashes before passing them to methods that expect plain Hash.

With a Block: Transforming Pairs

When you pass a block, it gets called with each key-value pair and expects a 2-element array return value:

h = { foo: 0, bar: 1, baz: 2 }

h.to_h { |key, value| [value, key] }
# => { 0 => :foo, 1 => :bar, 2 => :baz }

The block returns [new_key, new_value]. Those pairs become the new hash. This is how you transform both keys and values in one pass.

Practical Use Cases

Swapping Keys and Values

{ a: 1, b: 2 }.to_h { |k, v| [v, k] }
# => { 1 => :a, 2 => :b }

Filtering and Transforming

scores = { alice: 95, bob: 82, carol: 98 }

# Keep only keys that are symbols, and double the values
scores.to_h { |k, v| [k, v * 2] if k.is_a?(Symbol) }
# => { alice: 190, bob: 164, carol: 196 }

Since the block must return a 2-element array, returning nil drops that pair:

h = { a: 1, b: 2, c: 3 }

h.to_h { |k, v| v.even? ? [k, v] : nil }
# => { b: 2 }

Converting from Enumerable Operations

Many Enumerable methods return arrays of arrays, not hashes. to_h converts them:

# group_by returns { group_label => [[k,v], [k,v]] }
users = { alice: 28, bob: 35, carol: 28 }
grouped = users.group_by { |_k, v| v }

# Each group is [[key, value], [key, value]] — not a hash
grouped.transform_values { |pairs| pairs.to_h }
# => { 28 => { alice: 28, carol: 28 }, 35 => { bob: 35 } }

Merging with Transform

h1 = { a: 1, b: 2 }
h2 = { b: 3, c: 4 }

# Merge and transform in one pass
h1.merge(h2).to_h { |k, v| [k, v * 10] }
# => { a: 10, b: 30, c: 40 }

Converting Other Collections

to_h also works on arrays of pairs:

[[:a, 1], [:b, 2]].to_h
# => { a: 1, b: 2 }

This is Enumerable#to_h, which Hash includes. The result is a plain Hash.

Keyword Arguments

Ruby 3 dropped the auto-conversion of keyword argument hashes. to_h is useful for explicitly converting when you need to pass a hash as keyword arguments:

def greet(name:, greeting: "Hello")
  puts "#{greeting}, #{name}!"
end

opts = { name: "Alice", greeting: "Hi" }
greet(**opts)                          # works in Ruby 3
greet(**opts.to_h)                     # explicit conversion (redundant but clear)

Empty Hash

Calling to_h on an empty hash returns an empty hash (or a new empty hash for subclasses):

{}.to_h
# => {}

CustomHash.new.to_h
# => {}

See Also