From: Glenn Ritz on
Xavier Noria wrote:
> On Wed, Feb 24, 2010 at 10:40 PM, Glenn Ritz <glenn_ritz(a)yahoo.com>
> 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.

--
Posted via http://www.ruby-forum.com/.

From: Xavier Noria on
On Wed, Feb 24, 2010 at 11:17 PM, Glenn Ritz <glenn_ritz(a)yahoo.com> wrote:
> Xavier Noria wrote:
>> On Wed, Feb 24, 2010 at 10:40 PM, Glenn Ritz <glenn_ritz(a)yahoo.com>
>> 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'd use Active Support's #returning if available.

From: Robert Klemme on
2010/2/24 Xavier Noria <fxn(a)hashref.com>:
> On Wed, Feb 24, 2010 at 11:17 PM, Glenn Ritz <glenn_ritz(a)yahoo.com> wrote:
>> Xavier Noria wrote:
>>> On Wed, Feb 24, 2010 at 10:40 PM, Glenn Ritz <glenn_ritz(a)yahoo.com>
>>> 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/

From: Xavier Noria on
On Thu, Feb 25, 2010 at 8:26 AM, Robert Klemme
<shortcutter(a)googlemail.com> wrote:

> 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.

Yeah, much nicer.