what into elemento declarar create contadores como arreglo agregar ruby

into - ¿Cuándo es mejor usar un Struct en lugar de un Hash en Ruby?



ruby puts hash (5)

Un Ruby Struct permite generar una instancia con un conjunto de accesores:

# Create a structure named by its constant Customer = Struct.new(:name, :address) #=> Customer Customer.new("Dave", "123 Main") #=> #<Customer name="Dave", address="123 Main">

Esto parece conveniente y poderoso, sin embargo, un Hash hace algo bastante similar:

Customer = {:name => "Dave", :address => "123 Main"}

¿Cuáles son las situaciones del mundo real en las que debería preferir un Struct (y por qué), y cuáles son las advertencias o inconvenientes al elegir uno sobre el otro?


A Struct tiene la característica que puede obtener en sus elementos por índice y por nombre:

irb(main):004:0> Person = Struct.new(:name, :age) => Person irb(main):005:0> p = Person.new("fred", 26) => # irb(main):006:0> p[0] => "fred" irb(main):007:0> p[1] => 26 irb(main):008:0> p.name => "fred" irb(main):009:0> p.age => 26

lo que a veces es útil.


Aquí hay puntos de referencia más legibles para aquellos que aman las métricas de IPS (iteración por segundo):

Para pequeños casos:

require ''benchmark/ips'' require ''ostruct'' MyStruct = Struct.new(:a) Benchmark.ips do |x| x.report(''hash'') { a = { a: 1 }; a[:a] } x.report(''struct'') { a = MyStuct.new(1); a.a } x.report(''ostruct'') { a = OpenStruct.new(a: 1); a.a } x.compare! end

resultados:

Warming up -------------------------------------- hash 147.162k i/100ms struct 171.949k i/100ms ostruct 21.086k i/100ms Calculating ------------------------------------- hash 2.608M (± 3.1%) i/s - 13.097M in 5.028022s struct 3.680M (± 1.8%) i/s - 18.399M in 5.001510s ostruct 239.108k (± 5.5%) i/s - 1.202M in 5.046817s Comparison: struct: 3679772.2 i/s hash: 2607565.1 i/s - 1.41x slower ostruct: 239108.4 i/s - 15.39x slower

Para la lista enorme:

require ''benchmark/ips'' require ''ostruct'' MyStruct = Struct.new(:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m, :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z) Benchmark.ips do |x| x.report(''hash'') do hash = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 } hash[:a]; hash[:b]; hash[:c]; hash[:d]; hash[:e]; hash[:f]; hash[:g]; hash[:h]; hash[:i]; hash[:j]; hash[:k]; hash[:l]; hash[:m]; hash[:n]; hash[:o]; hash[:p]; hash[:q]; hash[:r]; hash[:s]; hash[:t]; hash[:u]; hash[:v]; hash[:w]; hash[:x]; hash[:y]; hash[:z] end x.report(''struct'') do struct = MyStruct.new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26) struct.a;struct.b;struct.c;struct.d;struct.e;struct.f;struct.g;struct.h;struct.i;struct.j;struct.k;struct.l;struct.m;struct.n;struct.o;struct.p;struct.q;struct.r;struct.s;struct.t;struct.u;struct.v;struct.w;struct.x;struct.y;struct.z end x.report(''ostruct'') do ostruct = OpenStruct.new( a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, u: 21, v: 22, w: 23, x: 24, y: 25, z: 26) ostruct.a;ostruct.b;ostruct.c;ostruct.d;ostruct.e;ostruct.f;ostruct.g;ostruct.h;ostruct.i;ostruct.j;ostruct.k;ostruct.l;ostruct.m;ostruct.n;ostruct.o;ostruct.p;ostruct.q;ostruct.r;ostruct.s;ostruct.t;ostruct.u;ostruct.v;ostruct.w;ostruct.x;ostruct.y;ostruct.z; end x.compare! end

resultados:

Warming up -------------------------------------- hash 51.741k i/100ms struct 62.346k i/100ms ostruct 1.010k i/100ms Calculating ------------------------------------- hash 603.104k (± 3.9%) i/s - 3.053M in 5.070565s struct 780.005k (± 3.4%) i/s - 3.928M in 5.041571s ostruct 11.321k (± 3.4%) i/s - 56.560k in 5.001660s Comparison: struct: 780004.8 i/s hash: 603103.8 i/s - 1.29x slower ostruct: 11321.2 i/s - 68.90x slower

Conclusión

Como puede ver, la estructura es un poco más rápida, pero requiere definir los campos de la estructura antes de usarla, por lo que si el rendimiento es realmente importante para usted, use la estructura;)


Con respecto a los comentarios sobre la velocidad de uso de Hashes, Struct o OpenStruct: Hash siempre ganará para uso general. Es la base de OpenStruct sin la formación de hielo adicional, por lo que no es tan flexible, pero es delgado y mezquino.

Usando Ruby 2.4.1:

require ''fruity'' require ''ostruct'' def _hash h = {} h[''a''] = 1 h[''a''] end def _struct s = Struct.new(:a) foo = s.new(1) foo.a end def _ostruct person = OpenStruct.new person.a = 1 person.a end compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Running each test 4096 times. Test will take about 2 seconds. # >> a_hash is faster than an_ostruct by 13x ± 1.0 # >> an_ostruct is similar to a_struct

Usando definiciones más concisas del hash y OpenStruct:

require ''fruity'' require ''ostruct'' def _hash h = {''a'' => 1} h[''a''] end def _struct s = Struct.new(:a) foo = s.new(1) foo.a end def _ostruct person = OpenStruct.new(''a'' => 1) person.a end compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Running each test 4096 times. Test will take about 2 seconds. # >> a_hash is faster than an_ostruct by 17x ± 10.0 # >> an_ostruct is similar to a_struct

Si la estructura, Hash o Struct o OpenStruct se define una vez y luego se usa muchas veces, entonces la velocidad de acceso se vuelve más importante y un Struct comienza a brillar:

require ''fruity'' require ''ostruct'' HSH = {''a'' => 1} def _hash HSH[''a''] end STRCT = Struct.new(:a).new(1) def _struct STRCT.a end OSTRCT = OpenStruct.new(''a'' => 1) def _ostruct OSTRCT.a end puts "Ruby version: #{RUBY_VERSION}" compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Ruby version: 2.4.1 # >> Running each test 65536 times. Test will take about 2 seconds. # >> a_struct is faster than a_hash by 4x ± 1.0 # >> a_hash is similar to an_ostruct

Sin embargo, tenga en cuenta que el Struct es solo 4 veces más rápido que el Hash para acceder, mientras que el Hash es 17 veces más rápido para la inicialización, asignación y acceso. Tendrá que averiguar cuál es el mejor para usar según las necesidades de una aplicación en particular. Tiendo a usar Hashes para uso general como resultado.

Además, la velocidad de uso de OpenStruct ha mejorado mucho con los años; Solía ​​ser más lento que Struct según los puntos de referencia que he visto en el pasado y en comparación con 1.9.3-p551:

require ''fruity'' require ''ostruct'' def _hash h = {} h[''a''] = 1 h[''a''] end def _struct s = Struct.new(:a) foo = s.new(1) foo.a end def _ostruct person = OpenStruct.new person.a = 1 person.a end puts "Ruby version: #{RUBY_VERSION}" compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Ruby version: 1.9.3 # >> Running each test 4096 times. Test will take about 2 seconds. # >> a_hash is faster than a_struct by 7x ± 1.0 # >> a_struct is faster than an_ostruct by 2x ± 0.1

y:

require ''fruity'' require ''ostruct'' def _hash h = {''a'' => 1} h[''a''] end def _struct s = Struct.new(:a) foo = s.new(1) foo.a end def _ostruct person = OpenStruct.new(''a'' => 1) person.a end puts "Ruby version: #{RUBY_VERSION}" compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Ruby version: 1.9.3 # >> Running each test 4096 times. Test will take about 2 seconds. # >> a_hash is faster than a_struct by 7x ± 1.0 # >> a_struct is faster than an_ostruct by 2x ± 1.0

y:

require ''fruity'' require ''ostruct'' HSH = {''a'' => 1} def _hash HSH[''a''] end STRCT = Struct.new(:a).new(1) def _struct STRCT.a end OSTRCT = OpenStruct.new(''a'' => 1) def _ostruct OSTRCT.a end puts "Ruby version: #{RUBY_VERSION}" compare do a_hash { _hash } a_struct { _struct } an_ostruct { _ostruct } end # >> Ruby version: 1.9.3 # >> Running each test 32768 times. Test will take about 1 second. # >> a_struct is faster than an_ostruct by 3x ± 1.0 # >> an_ostruct is similar to a_hash


Es principalmente el rendimiento. Struct es mucho más rápido, por orden de magnitudes. Y consume menos memoria en comparación con Hash o OpenStruct. Más información aquí: ¿ Cuándo debo usar Struct vs. OpenStruct?


Personalmente utilizo una estructura en los casos en los que quiero que una parte de los datos actúe como una recopilación de datos en lugar de acoplarlos de forma flexible bajo un Hash .

Por ejemplo, he creado un script que descarga videos de Youtube y allí tengo una estructura para representar un video y para comprobar si todos los datos están en su lugar:

Video = Struct.new(:title, :video_id, :id) do def to_s "http://youtube.com/get_video.php?t=#{id}&video_id=#{video_id}&fmt=18" end def empty? @title.nil? and @video_id.nil? and @id.nil? end end

Más adelante, en mi código, tengo un bucle que recorre todas las filas de la página HTML de la fuente de videos hasta que empty? no devuelve verdad

Otro ejemplo que he visto es la clase de configuración de James Edward Gray II , que utiliza OpenStruct para agregar fácilmente las variables de configuración cargadas desde un archivo externo:

#!/usr/bin/env ruby -wKU require "ostruct" module Config module_function def load_config_file(path) eval <<-END_CONFIG config = OpenStruct.new #{File.read(path)} config END_CONFIG end end # configuration_file.rb config.db = File.join(ENV[''HOME''], ''.cool-program.db'') config.user = ENV[''USER''] # Usage: Config = Config.load_config(''configuration_file.rb'') Config.db # => /home/ba/.cool-program.db Config.user # => ba Config.non_existant # => Nil

La diferencia entre Struct y OpenStruct es que Struct solo responde a los atributos que ha establecido, OpenStruct responde a cualquier conjunto de atributos, pero aquellos sin un conjunto de valores devolverán Nil