Flattening a nested hash to a single hash in Ruby
Hideaki Ishii
Posted on June 9, 2019
When using Ruby, you may sometimes need to flatten a nested hash like:
{
:foo => "bar",
:hello => {
:world => "Hello World",
:bro => "What's up dude?",
},
:a => { :b => { :c => "d" } }
}
to a single hash like:
{
:foo => "bar",
:"hello.world" => "Hello World",
:"hello.bro" => "What's up dude?",
:"a.b.c" => "d"
}
Today, I introduce a way to achieve it referring to a post in Stack Overflow.
Let’s implement
def flatten_hash_from(hash)
hash.each_with_object({}) do |(key, value), memo|
next flatten_hash_from(value).each do |k, v|
memo["#{key}.#{k}".intern] = v
end if value.is_a? Hash
memo[key] = value
end
end
Using Enumberable#each_with_object
recursively helps us achieve it.
Let’s deep dive into how it works.
How it works
First,
key = :foo
,value = "bar"
is given. the value is not a hash, somemo
becomes{ :foo => "bar" }
and the process continues.key = :hello
,value = { :world => "Hello World", :bro => "What's up dude?" }
is given. The value is a hash, soflatten_hash_from
is invoked again with the value.After STEP 2,
memo
is{}
again, which is different from the one in STEP 1. Then,key = :world
,value = "Hello World"
is given, which is not a hash, somemo
becomes{ :world => "Hello World" }
. Similarly,key = :bro
is given next, thenmemo
becomes{ :world => "Hello World", :bro => "What's up dude?" }
and the result is returned to STEP 2.From STEP 3, the process goes back to
each
part withkey = :hello
. Bymemo["#{key}.#{k}".intern] = v
,memo
becomes{ :foo => "bar", :"hello.world" => "Hello World", :"hello.bro" => "What's up dude?" }
.Next,
key = :a
,value = { :b => { :c => "d" } }
is given. The value is a hash then,flatten_hash_from
is invoked recursively like STEP2.flatten_hash_from
is invoked withkey = :b
,value = { :c => "d" }
.{ :c => "d" }
is returned to STEP 6.{ :"b.c" => "d" }
is returned to STEP 5.From STEP 5, the process goes back to
each
part withkey = :a
and{ :"a.b.c" => "d" }
is added tomemo
. It turns outmemo
is{ :foo => "bar", :"hello.world" => "Hello World", :"hello.bro" => "What's up dude?", :"a.b.c" => "d" }
, then the process completed.
References
Posted on June 9, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.