¿Cómo puedo convertir un hash en una estructura en ruby?Convierta un hash en una estructura
Teniendo en cuenta esto:
h = { :a => 1, :b => 2 }
Quiero una estructura tal que:
s.a == 1
s.b == 2
¿Cómo puedo convertir un hash en una estructura en ruby?Convierta un hash en una estructura
Teniendo en cuenta esto:
h = { :a => 1, :b => 2 }
Quiero una estructura tal que:
s.a == 1
s.b == 2
Si no lo hace específicamente h AVE a ser un Struct
y en su lugar puede ser una OpenStruct
:
pry(main)> require 'ostruct'
pry(main)> s = OpenStruct.new(h)
=> #<OpenStruct a=1, b=2>
pry(main)> puts s.a, s.b
1
2
A continuación se crea una estructura de un hash de una manera fiable (ya fin de hash no está garantizada en rubí) :
s = Struct.new(*(k = h.keys)).new(*h.values_at(*k))
Desde un orden clave hash está garantizada en Ruby 1.9+:
Struct.new(*h.keys).new(*h.values)
Es bueno saberlo.Pensé que lo había leído en alguna parte pero no recordaba dónde. ¡Gracias! – alf
Esto no parece funcionar (al menos en Ruby 2.2.0): 'Struct.new (* h.keys)' plantea: 'NameError: identifier my_key necesita ser constante' – Joe
@Joe funciona bien. Creo que usaste llaves de cadena para tu hash, que es la causa del error. El error le indica que necesita un valor constante, es decir, un símbolo en lugar de una cadena. Puedo reproducir el error en 2.1.5, desaparece si cambio al símbolo. – ehsanul
He aquí un ejemplo para asignar los valores a la orden de la struct:
require 'securerandom'
Message = Struct.new(:to, :from, :message, :invitee)
message_params = {from: "[email protected]", to: "[email protected]",
invitee: SecureRandom.uuid, message: "hello"}
if Message.members.sort == message_params.keys.sort
# Do something with the return struct object here
Message.new *Message.members.map {|k| message_params[k] }
else
raise "Invalid keys for Message"
end
Si ya ha definido una estructura, y que desea crear una instancia con un hash:
Person = Struct.new(:first_name, :last_name, :age)
person_hash = { first_name: "Foo", last_name: "Bar", age: 29 }
person = Person.new(*person_hash.values_at(*Person.members))
=> #<struct Person first_name="Foo", last_name="Bar", age=29>
Esta debería ser la respuesta aceptada :). ¡Gracias! – Ven
¡Gracias! Estoy diseñando una gema que se puede invocar desde un comando o desde un código externo, cada una de las opciones de suministro (utilizando OptionParser o Hash, respectivamente). Esto permite un fácil filtrado de opciones durante la inicialización de mi gema. Y el Struct también ayuda a auto-documentar las opciones permitidas. – Excalibur
require 'ds_hash'
data = {a: {b: 123 }}.to_struct
data.a.b == 123 # true
data.a == {b: 123 } # true
Habiendo Hash#to_struct
es bastante práctico:
class Hash
def to_struct
Struct.new(*keys).new(*values)
end
end
Y algunos ejemplos:
>> { a: 1, b: 2 }.to_struct
=> #<struct a=1, b=2>
>> { a: 1, b: 2 }.to_struct.a
=> 1
>> { a: 1, b: 2 }.to_struct.b
=> 2
>> { a: 1, b: 2 }.to_struct.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
profundo to_struct
que trabaja con matrices:
class Array
def to_struct
map { |value| value.respond_to?(:to_struct) ? value.to_struct : value }
end
end
class Hash
def to_struct
Struct.new(*keys).new(*values.to_struct)
end
end
Es bueno, pero si su hash json '['name']', necesita simbolizar las teclas. – 7urkm3n
Nunca había oído hablar de 'OpenStruct' antes. ¡Eso es genial! ¡Gracias! – alf
Tenga en cuenta que OpenStructs puede ser increíblemente lento de usar. Está bien para una pequeña cantidad de objetos pequeños, pero se escalan mal. Más información aquí: http://stackoverflow.com/questions/1177594/ruby-struct-vs-openstruct –
@AFaderDarkly Creo que sus problemas de velocidad están bien documentados, pero gracias. –