1

I want to transform nested hashes into multidimensional arrays recursivley.

This is my current code:

def deep_to_a(hash)
  return  hash.to_a.each {|k, v|
    if k.is_a?(Hash) then
      hash[k.to_a] = hash.delete(k)
      deep_to_a(k)
    elsif v.is_a?(Hash) then
      hash[k] = hash[k].to_a
      if hash[k].any?{|k, v| k.is_a?(Hash) || v.is_a?(Hash)}
        deep_to_a(v)
      end
    end
  }
end

I want to get:

h = {11=>{12=>13, 14=>15}, 16=>17}
p deep_to_a(h) # => [[11, [[12, 13], [14, 15]]], [16, 17]] 

But I get

[[11, {12=>13, 14=>15}], [16, 17]]

How can I make it work?

1
  • k.is_a?(Hash) – none of your keys is a hash. Commented May 17, 2018 at 14:54

2 Answers 2

2

A destructive function is hard to debug. In this case, map is better than each + destructive assignment.

The result of hash.to_a is an array, so your iteration |k, v| is incorrect.

def deep_to_a(hash)
  hash.map do |v|
    if v.is_a?(Hash) or v.is_a?(Array) then
      deep_to_a(v)
    else
      v
    end
  end
end

h = {11=>{12=>13, 14=>15}, 16=>17}
p deep_to_a(h)
# [[11, [[12, 13], [14, 15]]], [16, 17]]
Sign up to request clarification or add additional context in comments.

3 Comments

I was on the track, but this is great.
You don't need return either, as the return value from the block is the last value computed, so it is returned by the method. Note that you could instead (but not better) write, case v; when Hash, Array; deep_to_a(v); else v; end. Note then is optional with an if and generally not used.
@CarySwoveland Certainly... I updated my post. Thankyou again!
1
def deep_to_a(h)
  h.map { |k,v| [k, Hash === v ? deep_to_a(v) : v] }
end

deep_to_a({11=>{12=>13, 14=>15}, 16=>17})
  #=> [[11, [[12, 13], [14, 15]]], [16, 17]]

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.