0

I have an array of strings of unknown length (but let's say up to 5). I have also an empty hash h = {} and a value.

I want to transform the array and the value to hash like this:

val = 1
h = {}
a = ['a', 'b', 'c', 'd']
# result I want:
{
  'a' => {
    'b' => {
      'c' => {
        'd' => 1
      }
    }
  }
}

What's important is that some of the keys might already exist (created in a loop iteration before). So I might have:

val = 2
h = {'a' => {'b' => {'c' => {'d' => 1}}}}
a = ['a', 'b', 'c', 'e']
# result I want:
{
  'a' => {
    'b' => {
      'c' => {
        'd' => 1,
        'e' => 2
      }
    }
  }
}

Any ideas on how to do that?

1 Answer 1

4

Once again, inject to the rescue:

def dredge(hash, list, value = nil)
  # Snip off the last element
  *list, tail = list

  # Iterate through the elements in the path...
  final = list.inject(hash) do |h, k|
    # ...and populate with a hash if necessary.
    h[k] ||= { }
  end

  # Add on the final value
  final[tail] = value

  hash
end

This could be improved a little depending on how resilient you need it to be on things like zero-length lists and so on.

Here it is applied:

h = {}
a = ['a', 'b', 'c', 'd']
dredge(h, a, 1)
# => {"a"=>{"b"=>{"c"=>{"d"=>1}}}}

h = {'a' => {'b' => {'c' => {'d' => 1}}}}
a = ['a', 'b', 'c', 'e']

dredge(h, a, 2)
# => {"a"=>{"b"=>{"c"=>{"d"=>1, "e"=>2}}}}
Sign up to request clarification or add additional context in comments.

2 Comments

I was about to post the same :-) You could use *list, tail = list to avoid mutating list
True, that's probably a better idea. Let me change that.

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.