Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting ruby hash values by an array of keys

What I'm aiming to do is to create an object which is initialized with a hash and then query this object in order to get values from that hash. To make things clearer here's a rough example of what I mean:

class HashHolder
  def initialize(hash)
    @hash = hash
  end

  def get_value(*args)
    # What are my possibilities here?
  end
end

holder = HashHolder.new({:a => { :b => { :c => "value" } } } )
holder.get_value(:a, :b, :c) # should return "value"

I know I can perform iteration on the arguments list as in:

def get_value(*args)
  value = @hash
  args.each do |k|
    value = value[k]
  end
  return value
end

But if I plan to use this method a lot this is going to degrade my performance dramatically when all I want to do is to access a hash value.

Any suggestions on that?

like image 618
Erez Rabih Avatar asked Nov 27 '12 08:11

Erez Rabih


People also ask

How can you get all the values of a hash in an array Ruby?

We can use the values method to return all the values of a hash in Ruby.

How do you hash an array in Ruby?

In Ruby, a hash is a collection of key-value pairs. A hash is denoted by a set of curly braces ( {} ) which contains key-value pairs separated by commas. Each value is assigned to a key using a hash rocket ( => ). Calling the hash followed by a key name within brackets grabs the value associated with that key.

How do you iterate through a hash?

Use #each to iterate over a hash.


2 Answers

To update the answer since it's been a while since it was asked.

(tested in ruby 2.3.1)

You have a hash like this:

my_hash = {:a => { :b => { :c => "value" } } }

The question asked:

my_hash.get_value(:a, :b, :c) # should return "value"

Answer: Use 'dig' instead of get_value, like so:

my_hash.dig(:a,:b,:c) # returns "value"

Since the title of the question is misleading (it should be something like: how to get a value inside a nested hash with an array of keys), here is an answer to the question actually asked:

Getting ruby hash values by an array of keys

Preparation:

my_hash = {:a => 1, :b => 3, :d => 6}
my_array = [:a,:d]

Answer:

my_hash.values_at(*my_array) #returns [1,6]
like image 97
Ekkstein Avatar answered Oct 24 '22 23:10

Ekkstein


def get_value(*args)
  args.inject(@hash, &:fetch)
end


In case you want to avoid iteration at lookup (which I do not feel necessary), then you need to flatten the hash to be stored:
class HashHolder
  def initialize(hash)
    while hash.values.any?{|v| v.kind_of?(Hash)}
      hash.to_a.each{|k, v| if v.kind_of?(Hash); hash.delete(k).each{|kk, vv| hash[[*k, kk]] = vv} end}
    end
    @hash = hash
  end
  def get_value(*args)
    @hash[args]
  end
end
like image 28
sawa Avatar answered Oct 24 '22 22:10

sawa