2

In Ruby, I want to do something like this,

I have a hash of hash built like this.

h = {1 => {2 => {3 => "three"}},'a' => { 'b' => { 'c' => "basd"}}}
=> {"a"=>{"b"=>{"c"=>"basd"}}, 1=>{2=>{3=>"three"}}}

If I have an array with values like this.

a = [1, 2, 3]

I want to have a method which will use the array values to index nested keys in my hash and return the value pointed by last key (as guided by previous array/keys) for eg.

getHashValue([1,2,3]) should return "three" => h[1][2][3]

if a = ['a','b', 'c'] then the return value should be basd.

How to get this done?

warren
  • 32,620
  • 21
  • 85
  • 124
user2562153
  • 317
  • 1
  • 3
  • 12

4 Answers4

4

And then there's:

keys.inject(hash, :fetch)

or for earlier Ruby versions:

keys.inject(hash) {|h, k| h[k]}

If you did want to use recursion, a more Rubyesque approach would be:

def get_value(obj, keys)
  keys.empty? ? obj : get_value(obj[keys[0]], keys[1..-1])
end
Peter Alfvin
  • 28,599
  • 8
  • 68
  • 106
  • Anything wrong in my try? irb(main):2552:0> h => {"a"=>{"b"=>{"c"=>"basd"}}, 1=>{2=>{3=>"three"}}} irb(main):2553:0> a = [1,2,3] => [1, 2, 3] irb(main):2554:0> a.inject(h, :[]) ArgumentError: wrong number of arguments (2 for 1) from (irb):2554:in `inject' from (irb):2554 irb(main):2555:0> a.inject(h, :fetch) ArgumentError: wrong number of arguments (2 for 1) from (irb):2555:in `inject' from (irb):2555 – user2562153 Jul 09 '13 at 07:44
  • @user2562153 I started with Ruby from 1.9.3. So if that's the case go with *megar* solution. – Arup Rakshit Jul 09 '13 at 08:53
  • In earlier versions of Ruby, such as yours, inject required a block, so the form you'd have to use is `keys.inject(hash) {|h, k| h[k]}` – Peter Alfvin Jul 09 '13 at 13:56
  • Hi Peter, inject now works with a block. Thanks for your tip. – user2562153 Jul 11 '13 at 06:28
3

Ruby 2.3.0 introduced a new method called dig on both Hash and Array that solves this problem entirely.

It returns nil if an element is missing at any level of nesting.

h1 = {}
h2 = { a: {} }
h3 = { a: { b: {} } }
h4 = { a: { b: { c: 100 } } }

h1.dig(:a, :b, :c) # => nil
h2.dig(:a, :b, :c) # => nil
h3.dig(:a, :b, :c) # => nil
h4.dig(:a, :b, :c) # => 100
user513951
  • 12,445
  • 7
  • 65
  • 82
2

Simple recursion

def getValue(hash, keys, i = 0)
  if i + 1 < keys.length
    getValue(hash[keys[i]], keys, i + 1)
  else
    hash[keys[i]]
  end
end

getValue(h, [1,2,3]) => "three"
getValue(h, ['a','b','c']) => "basd"
user229044
  • 232,980
  • 40
  • 330
  • 338
1
h = {1 => {2 => {3 => "three"}},'a' => { 'b' => { 'c' => "basd"}}}
a = ['a','b', 'c']
a.inject(h, :[]) # => "basd"

h = {1 => {2 => {3 => "three"}},'a' => { 'b' => { 'c' => "basd"}}}
a = [1, 2, 3]
a.inject(h, :[]) # => "three"
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317