0

Let's say I have a Hash like this:

my_hash = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}

And I want to convert every element inside the hash that is also a hash to be placed inside of an Array.

For example, I want the finished Hash to look like this:

{"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}

Here is what I've tried so far, but I need it to work recursively and I'm not quite sure how to make that work:

my_hash.each do |k,v|
  if v.class == Hash
    my_hash[k] = [] << v
  end
end
 => {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>{"c2"=>"c3"}}]}
5
  • @sergiotulentsev, now both answers are deleted. Both should be turned into community wiki answers. Commented Dec 23, 2015 at 17:50
  • @theTinMan: Hm, I see one still standing. No need to have them both. Commented Dec 23, 2015 at 17:52
  • @SergioTulentsev, Yes, the other was undeleted right after the comment-exchange. Commented Dec 23, 2015 at 17:55
  • Would it not be more convenient if all the hash values were arrays, as you could always check if h[k].is_a? Hash. Commented Dec 23, 2015 at 19:49
  • Why the down votes? I clearly state my need and my attempted solution? Commented Jan 12, 2016 at 15:48

2 Answers 2

4

You need to wrap your code into a method and call it recursively.

my_hash = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}

def process(hash)
    hash.each do |k,v|
      if v.class == Hash
        hash[k] = [] << process(v)
      end
    end
end

p process(my_hash)
#=> {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}
Sign up to request clarification or add additional context in comments.

2 Comments

Good one, Wand. You could alternatively write hash[k] = [process(v)].
@CarySwoveland I did not mess with the original code much, its pretty much what OP had. Feel free to update it as its community wiki
2

Recurring proc is another way around:

h = {"a"=>{"a1"=>"b1"}, "b"=>"b", "c"=>{"c1"=>{"c2"=>"c3"}}}
h.map(&(p = proc{|k,v| {k => v.is_a?(Hash) ? [p[*v]] : v}}))
 .reduce({}, &:merge)
# => {"a"=>[{"a1"=>"b1"}], "b"=>"b", "c"=>[{"c1"=>[{"c2"=>"c3"}]}]}

It can be done with single reduce, but that way things get even more obfuscated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.