From: Robert Klemme Date: 2010-02-25T16:26:11+09:00 Subject: Re: Iterate over hash of nested hashes 2010/2/24 Xavier Noria : > On Wed, Feb 24, 2010 at 11:17 PM, Glenn Ritz wrote: >> Xavier Noria wrote: >>> On Wed, Feb 24, 2010 at 10:40 PM, Glenn Ritz >>> wrote: >>> >>>> I'd like to be able to take a hash whose values are either hashes or >>>> some other object. If the values are hashes, I'd like to iterate over >>>> them and keep this up until the values aren't hashes.  And I won't know >>>> how many level there will be until the program is running.  Any >>>> suggestions? >>> >>> The iterator should yield... what? key, value pairs when it gets to a >>> leave? Only values? All pairs no matter the type of the value? >> >> If the Hash looks like this: >> >> {'en' => {'A' => 1, 'B' => {'C' => 3, 'D' => 'four' }} >> >> I'd like to be able to create a new hash that looks like this (it's for >> a gem that I am trying to write): >> >> {'en' => {'A' => Fixnum, 'B' => {'C' => Fixnum, 'D' => String }} >> >> So I think it should yield the key value pairs when it gets to a leaf, >> but it also seems like I will need more to be able to create the above >> hash. > > For example > > def classify_values(h) >  newh = {} >  h.each do |k, v| >    newh[k] = v.is_a?(Hash) ? classify_values(v) : v.class >  end >  newh > end > > p classify_values({'en' => {'A' => 1, 'B' => {'C' => 3, 'D' => 'four' }}}) I would do it a tad differently: def classify(o) case o when Hash h = {} o.each {|k,v| h[k] = classify(v)} h else o.class end end Advantage is that you can stuff anything in the method while your variant requires the argument to be a Hash. The difference may seem subtle but if you add more collection types for special treatment, you'll will notice a difference in effort to implement it. I can simply do def classify(o) case o when Hash h = {} o.each {|k,v| h[k] = classify(v)} h when Array o.map {|v| classify(v)} else o.class end end while you need to do a more complicated code change. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/