Hi,
I would like to take a nested hash that looks like this:
{"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}}
and turn it into an array of 2 element arrays like this:
[["a: b2: c2: ", 2], ["a: b: c: ", 1]]
Is there a simple way to do this? I wrote a method that iterates
through the nested hashes recursively, but it's a bit cumbersome.
on 2010-03-09 13:31
on 2010-03-09 13:52
On Tue, Mar 9, 2010 at 8:31 PM, Glenn Ritz <glenn_ritz@yahoo.com> wrote: > Hi, > > I would like to take a nested hash that looks like this: > > {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} > > and turn it into an array of 2 element arrays like this: > > [["a: b2: c2: ", 2], ["a: b: c: ", 1]] > My method: hash = {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} array = [] hash.keys.each do |k1| hash[k1].keys.each do |k2| hash[k1][k2].keys.each do |k3| array << ["#{k1}: #{k2}: #{k3}:",hash[k1][k2][k3]] end end end
on 2010-03-09 14:05
Jean G. wrote: > On Tue, Mar 9, 2010 at 8:31 PM, Glenn Ritz <glenn_ritz@yahoo.com> wrote: >> Hi, >> >> I would like to take a nested hash that looks like this: >> >> {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} >> >> and turn it into an array of 2 element arrays like this: >> >> [["a: b2: c2: ", 2], ["a: b: c: ", 1]] >> > > My method: > > hash = {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} > array = [] > > hash.keys.each do |k1| > hash[k1].keys.each do |k2| > hash[k1][k2].keys.each do |k3| > array << ["#{k1}: #{k2}: #{k3}:",hash[k1][k2][k3]] > end > end > end Thanks, Jean. It's a good solution. But it's dependent on there being 3 levels of hashes. What if you didn't know how many levels of nesting there was before executing the code? Suppose the hash looked like this instead: {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=> {"d2" => 2}}}}
on 2010-03-09 14:15
Glenn Ritz wrote: > Hi, > > I would like to take a nested hash that looks like this: > > {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} > > and turn it into an array of 2 element arrays like this: > > [["a: b2: c2: ", 2], ["a: b: c: ", 1]] > > Is there a simple way to do this? I wrote a method that iterates > through the nested hashes recursively, but it's a bit cumbersome. I think that's the right way, if the nesting depth is variable. One example: class Hash def flat_each(prefix="", &blk) each do |k,v| if v.is_a?(Hash) v.flat_each(prefix+k+": ", &blk) else yield prefix+k, v end end end end require 'enumerator' h = {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}} p h.to_enum(:flat_each).collect { |k,v| [k,v] }
on 2010-03-09 14:25
Perhaps a better solution is to yield an array of keys (being the 'path'
to reach the end node), because then the caller can choose how to
combine them.
class Hash
def flat_each(prefix=[], &blk)
each do |k,v|
if v.is_a?(Hash)
v.flat_each(prefix+[k], &blk)
else
yield prefix+[k], v
end
end
end
end
require 'enumerator'
h = {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=>2}}}
h = {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=> {"d2" => 2}}}}
p h.to_enum(:flat_each).collect { |k,v| [k.join(": "),v] }
h.flat_each do |k,v|
puts "#{k.join("/")} => #{v}"
end
on 2010-03-09 14:26
2010/3/9 Glenn Ritz <glenn_ritz@yahoo.com>: >>> [["a: b2: c2: ", 2], ["a: b: c: ", 1]] >> array << ["#{k1}: #{k2}: #{k3}:",hash[k1][k2][k3]] > {"a"=>{"b"=>{"c"=>1}, "b2"=>{"c2"=> {"d2" => 2}}}} Basically you want to do a DFS and store the path to the root for every leaf. Something like http://gist.github.com/326558 Kind regards robert
on 2011-06-24 00:27
I coded up a way to do this in a method without needing to monkey-patch
Hash: http://forr.st/~zaG
# Takes in a hash in input and merges it with an output hash to produce
a hash that is only one dimensional
# i.e. there are no nested elements in the hash
def make_hash_one_dimensional(input = {}, output = {}, options = {})
input.each do |key, value|
key = options[:prefix].nil? ? "#{key}" :
"#{options[:prefix]}#{options[:delimiter]||"_"}#{key}"
if value.is_a? Hash
make_hash_one_dimensional(value, output, :prefix => key,
:delimiter => "_")
else
output[key] = value
end
end
output
end
hash = {:a => {:b => {:c => {:d => {:e => "hi"}}}}, :f => "there"}
make_hash_one_dimensional(hash)
#=> {"f"=>"there", "a_b_c_d_e"=>"hi"}
From there it would be easy to turn this into an array. Enjoy
--
@schneems
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.