rails into create array ruby hash

ruby - into - ¿Cómo extraigo un sub hash de un hash?



hash.map ruby (12)

Aquí hay una comparación de rendimiento rápido de los métodos sugeridos, #select parece ser el más rápido

k = 1_000_000 Benchmark.bmbm do |x| x.report(''select'') { k.times { {a: 1, b: 2, c: 3}.select { |k, _v| [:a, :b].include?(k) } } } x.report(''hash transpose'') { k.times { Hash[ [[:a, :b], {a: 1, b: 2, c: 3}.fetch_values(:a, :b)].transpose ] } } x.report(''slice'') { k.times { {a: 1, b: 2, c: 3}.slice(:a, :b) } } end Rehearsal -------------------------------------------------- select 1.640000 0.010000 1.650000 ( 1.651426) hash transpose 1.720000 0.010000 1.730000 ( 1.729950) slice 1.740000 0.010000 1.750000 ( 1.748204) ----------------------------------------- total: 5.130000sec user system total real select 1.670000 0.010000 1.680000 ( 1.683415) hash transpose 1.680000 0.010000 1.690000 ( 1.688110) slice 1.800000 0.010000 1.810000 ( 1.816215)

El refinamiento se verá así:

module CoreExtensions module Extractable refine Hash do def extract(*keys) select { |k, _v| keys.include?(k) } end end end end

Y para usarlo:

using ::CoreExtensions::Extractable { a: 1, b: 2, c: 3 }.extract(:a, :b)

Tengo un hash:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}

¿Cuál es la mejor manera de extraer un sub hash como este?

h1.extract_subhash(:b, :d, :e, :f) # => {:b => :B, :d => :D} h1 #=> {:a => :A, :c => :C}


Aquí hay una solución funcional que puede ser útil si no está utilizando Ruby 2.5 y en el caso de que no quiera contaminar su clase Hash agregando un nuevo método:

slice_hash = -> keys, hash { hash.select { |k, _v| keys.include?(k) } }.curry

Luego puede aplicarlo incluso en hashes anidados:

my_hash = [{name: "Joe", age: 34}, {name: "Amy", age: 55}] my_hash.map(&slice_hash.([:name])) # => [{:name=>"Joe"}, {:name=>"Amy"}]


Este código inyecta la funcionalidad que está solicitando en la clase Hash:

class Hash def extract_subhash! *keys to_keep = self.keys.to_a - keys to_delete = Hash[self.select{|k,v| !to_keep.include? k}] self.delete_if {|k,v| !to_keep.include? k} to_delete end end

y produce los resultados que proporcionó:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D} p h1.extract_subhash!(:b, :d, :e, :f) # => {b => :B, :d => :D} p h1 #=> {:a => :A, :c => :C}

Nota: este método realmente devuelve las claves / valores extraídos.


Puede usar slice! (* Keys) que está disponible en las extensiones principales de ActiveSupport

initial_hash = {:a => 1, :b => 2, :c => 3, :d => 4} extracted_slice = initial_hash.slice!(:a, :c)

initial_hash ahora sería

{:b => 2, :d =>4}

extraído_slide sería ahora

{:a => 1, :c =>3}

Puede ver slice.rb in ActiveSupport 3.1.3


Si desea específicamente que el método devuelva los elementos extraídos, h1 permanecerá igual:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D} h2 = h1.select {|key, value| [:b, :d, :e, :f].include?(key) } # => {:b=>:B, :d=>:D} h1 = Hash[h1.to_a - h2.to_a] # => {:a=>:A, :c=>:C}

Y si quieres aplicar un parche a la clase Hash:

class Hash def extract_subhash(*extract) h2 = self.select{|key, value| extract.include?(key) } self.delete_if {|key, value| extract.include?(key) } h2 end end

Si solo desea eliminar los elementos especificados del hash, es mucho más fácil utilizar delete_if .

h1 = {:a => :A, :b => :B, :c => :C, :d => :D} h1.delete_if {|key, value| [:b, :d, :e, :f].include?(key) } # => {:a=>:A, :c=>:C} h1 # => {:a=>:A, :c=>:C}


si usa rieles, puede ser conveniente usar Hash.except

h = {a:1, b:2} h1 = h.except(:a) # {b:2}


Ruby 2.5 añadió Hash#slice :

h = { a: 100, b: 200, c: 300 } h.slice(:a) #=> {:a=>100} h.slice(:b, :c, :d) #=> {:b=>200, :c=>300}


ActiveSupport , al menos desde 2.3.8, proporciona cuatro métodos convenientes: #slice , #except y sus contrapartes destructivas: #slice! y #except! . Se mencionaron en otras respuestas, pero para resumirlas en un solo lugar:

x = {a: 1, b: 2, c: 3, d: 4} # => {:a=>1, :b=>2, :c=>3, :d=>4} x.slice(:a, :b) # => {:a=>1, :b=>2} x # => {:a=>1, :b=>2, :c=>3, :d=>4} x.except(:a, :b) # => {:c=>3, :d=>4} x # => {:a=>1, :b=>2, :c=>3, :d=>4}

Tenga en cuenta los valores de retorno de los métodos de explosión. No solo adaptarán el hash existente, sino que también devolverán las entradas eliminadas (no guardadas). The Hash#except! se adapta mejor al ejemplo dado en la pregunta:

x = {a: 1, b: 2, c: 3, d: 4} # => {:a=>1, :b=>2, :c=>3, :d=>4} x.except!(:c, :d) # => {:a=>1, :b=>2} x # => {:a=>1, :b=>2}

ActiveSupport no requiere raíles completos, es bastante liviano. De hecho, muchas gemas que no son de rieles dependen de ello, así que lo más probable es que ya lo tengas en Gemfile.lock. No es necesario extender la clase Hash por su cuenta.


Si usa rieles , Hash#slice es el camino a seguir.

{:a => :A, :b => :B, :c => :C, :d => :D}.slice(:a, :c) # => {:a => :A, :c => :C}

Si no utiliza los rieles , Hash # values_at devolverá los valores en el mismo orden en que los solicitó para que pueda hacer esto:

def slice(hash, *keys) Hash[ [keys, hash.values_at(*keys)].transpose] end def except(hash, *keys) desired_keys = hash.keys - keys Hash[ [desired_keys, hash.values_at(*desired_keys)].transpose] end

ex:

slice({foo: ''bar'', ''bar'' => ''foo'', 2 => ''two''}, ''bar'', 2) # => {''bar'' => ''foo'', 2 => ''two''} except({foo: ''bar'', ''bar'' => ''foo'', 2 => ''two''}, ''bar'', 2) # => {:foo => ''bar''}

Explicación:

Fuera de {:a => 1, :b => 2, :c => 3} queremos {:a => 1, :b => 2}

hash = {:a => 1, :b => 2, :c => 3} keys = [:a, :b] values = hash.values_at(*keys) #=> [1, 2] transposed_matrix =[keys, values].transpose #=> [[:a, 1], [:b, 2]] Hash[transposed_matrix] #=> {:a => 1, :b => 2}

Si siente que el parche de monos es el camino a seguir, lo siguiente es lo que quiere:

module MyExtension module Hash def slice(*keys) ::Hash[[keys, self.values_at(*keys)].transpose] end def except(*keys) desired_keys = self.keys - keys ::Hash[[desired_keys, self.values_at(*desired_keys)].transpose] end end end Hash.include MyExtension::Hash


class Hash def extract(*keys) key_index = Hash[keys.map{ |k| [k, true] }] # depends on the size of keys partition{ |k, v| key_index.has_key?(k) }.map{ |group| Hash[group] } end end h1 = {:a => :A, :b => :B, :c => :C, :d => :D} h2, h1 = h1.extract(:b, :d, :e, :f)


h1 = {:a => :A, :b => :B, :c => :C, :d => :D} keys = [:b, :d, :e, :f] h2 = (h1.keys & keys).each_with_object({}) { |k,h| h.update(k=>h1.delete(k)) } #=> {:b => :B, :d => :D} h1 #=> {:a => :A, :c => :C}


module HashExtensions def subhash(*keys) keys = keys.select { |k| key?(k) } Hash[keys.zip(values_at(*keys))] end end Hash.send(:include, HashExtensions) {:a => :A, :b => :B, :c => :C, :d => :D}.subhash(:a) # => {:a => :A}