How to iterate over nested hashes?

Hi,

I have a data structure like this: {1=>{“foo”=>[“bar”, “baz”]}}

…and I can iterate over it with this:

c.values.each do |foo|
foo.values.each do |bar|
bar.each do |baz|
p baz
end
end
end

But why can’t I do this? (fails):

c.values.each.values.each.each do |foo|
p foo
end

Any help much appreciated!

Andrew S. wrote in post #1068825:

But why can’t I do this? (fails):

c.values.each.values.each.each do |foo|
p foo
end

Because that’s not how “each” works. You cannot call a method on “each”
in order to call it on every element. The “each” method without a block
returns an Enumerator.

So you’ll either have to stick with the solution above or write your own
method. Or you should rethink the structure of your data. A deeply
nested hash or array is almost always bad design and should be replaced
with with an appropriate object (like a table, a tree or whatever fits
best).

By the way, replace “values.each” with “each_value”. This is easier to
read and doesn’t create an array with all values.

Thanks. I was hoping that there was some super clean Ruby way to do
this, but apparently not. Back to the drawing board!

Well, even if you could do that, I don’t find “each.each.each”
particularly clean. So it’s really a problem of the data structure.

On Mon, 16 Jul 2012 05:36:29 +0900
“Andrew S.” [email protected] wrote:

end

You can do something like this (just an idea)

module Enumerable
def recursive_each &block
(respond_to?(:each_value) ? each_value : each).each do |v|
if v.respond_to? :recursive_each
v.recursive_each(&block)
else
yield v
end
end
end
end

c = {1=>{“foo”=>[“bar”, “baz”]}}

c.recursive_each do |v|
puts v
end


Sincerely yours,
Aleksey V. Zapparov A.K.A. ixti
FSF Member #7118
Mobile Phone: +34 677 990 688
Homepage: http://www.ixti.net
JID: [email protected]

*Origin: Happy Hacking!