/ / Obtención de valores de hash de rubí mediante una serie de claves: ruby-on-rails, ruby, arrays, hash

Obtener valores de hash de ruby ​​mediante una matriz de claves: ruby-on-rails, ruby, arrays, hash

Lo que quiero hacer es crear un objeto.que se inicializa con un hash y luego consulta este objeto para obtener valores de ese hash. Para aclarar las cosas aquí es un ejemplo aproximado de lo que quiero decir:

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"

Sé que puedo realizar una iteración en la lista de argumentos como en:

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

Pero si planeo usar mucho este método, esto va a degradar dramáticamente mi rendimiento cuando lo único que quiero hacer es acceder a un valor de hash.

¿Alguna sugerencia sobre eso?

Respuestas

7 para la respuesta № 1

Para actualizar la respuesta ya que ha pasado un tiempo desde que se solicitó.

(probado en rubí 2.3.1)

Tienes un hash como este:

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

La pregunta formulada:

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

Respuesta: Use "dig" en lugar de get_value, así:

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

Dado que el título de la pregunta es engañoso (debería ser algo así como: cómo obtener un valor dentro de un hash anidado con una matriz de claves), aquí hay una respuesta a la pregunta realmente formulada:

Obtención de valores hash ruby ​​por una matriz de claves

Preparación:

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

Responder:

my_hash.values_at(*my_array) #returns [1,6]

4 para la respuesta № 2
def get_value(*args)
args.inject(@hash, &:fetch)
end


En caso de que quiera evitar la iteración en la búsqueda (lo que no me parece necesario), entonces necesita aplanar el hash para almacenarlo:

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

-3 para la respuesta № 3

Si sabe que la estructura del hash está siempre en ese formato, simplemente puede hacerlo:

holder[:a][:b][:c]

... devuelve "valor".