rails example ruby-on-rails ruby ruby-on-rails-3 hashmap ruby-hash

ruby-on-rails - example - hash en ruby on rails



¿Cómo eliminar una clave de Hash y obtener el hash restante en Ruby/Rails? (13)

Para agregar un nuevo par a Hash hago:

{:a => 1, :b => 2}.merge!({:c => 3}) #=> {:a => 1, :b => 2, :c => 3}

¿Hay una manera similar de eliminar una clave de Hash?

Esto funciona:

{:a => 1, :b => 2}.reject! { |k| k == :a } #=> {:b => 2}

pero esperaría tener algo como:

{:a => 1, :b => 2}.delete!(:a) #=> {:b => 2}

Es importante que el valor de retorno sea el hash restante, por lo que podría hacer cosas como:

foo(my_hash.reject! { |k| k == my_key })

en una linea


¿Por qué no solo usar:

hash.delete(key)


En lugar de parchear monos o incluir bibliotecas grandes innecesariamente, puede usar refinamientos si está usando Ruby 2 :

module HashExtensions refine Hash do def except!(*candidates) candidates.each { |candidate| delete(candidate) } self end def except(*candidates) dup.remove!(candidates) end end end

Puede usar esta función sin afectar otras partes de su programa, o tener que incluir grandes bibliotecas externas.

class FabulousCode using HashExtensions def incredible_stuff delightful_hash.except(:not_fabulous_key) end end


Esta es una forma de una línea para hacerlo, pero no es muy legible. Recomiendo usar dos líneas en su lugar.

use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)


Esto también funcionaría: hash[hey] = nil


Fue genial si eliminar devolver el par de eliminación del hash. Estoy haciendo esto:

hash = {a: 1, b: 2, c: 3} {b: hash.delete(:b)} # => {:b=>2} hash # => {:a=>1, :c=>3}


Hay muchas formas de eliminar una clave de un hash y obtener el hash restante en Ruby.

  1. .slice => .slice claves seleccionadas y no las eliminará del hash original

    2.2.2 :074 > hash = {"one"=>1, "two"=>2, "three"=>3} => {"one"=>1, "two"=>2, "three"=>3} 2.2.2 :075 > hash.slice("one","two") => {"one"=>1, "two"=>2} 2.2.2 :076 > hash => {"one"=>1, "two"=>2, "three"=>3}

  2. .delete => Eliminará las claves seleccionadas del hash original (puede aceptar solo una clave y no más de una)

    2.2.2 :094 > hash = {"one"=>1, "two"=>2, "three"=>3} => {"one"=>1, "two"=>2, "three"=>3} 2.2.2 :095 > hash.delete("one") => 1 2.2.2 :096 > hash => {"two"=>2, "three"=>3}

  3. .except => .except las claves restantes pero no eliminará nada del hash original

    2.2.2 :097 > hash = {"one"=>1, "two"=>2, "three"=>3} => {"one"=>1, "two"=>2, "three"=>3} 2.2.2 :098 > hash.except("one","two") => {"three"=>3} 2.2.2 :099 > hash => {"one"=>1, "two"=>2, "three"=>3}

  4. .delete_if => En caso de que necesite eliminar una clave basada en un valor. Obviamente, eliminará las claves correspondientes del hash original

    2.2.2 :115 > hash = {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1} => {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1} 2.2.2 :116 > value = 1 => 1 2.2.2 :117 > hash.delete_if { |k,v| v == value } => {"two"=>2, "three"=>3} 2.2.2 :118 > hash => {"two"=>2, "three"=>3}

Resultados basados ​​en Ruby 2.2.2.


Oneliner plain ruby, solo funciona con ruby> 1.9.x:

1.9.3p0 :002 > h = {:a => 1, :b => 2} => {:a=>1, :b=>2} 1.9.3p0 :003 > h.tap { |hs| hs.delete(:a) } => {:b=>2}

Tap método Tap siempre devuelve el objeto sobre el que se invoca ...

De lo contrario, si ha requerido active_support/core_ext/hash (que se requiere automáticamente en cada aplicación de Rails), puede usar uno de los siguientes métodos según sus necesidades:

➜ ~ irb 1.9.3p125 :001 > require ''active_support/core_ext/hash'' => true 1.9.3p125 :002 > h = {:a => 1, :b => 2, :c => 3} => {:a=>1, :b=>2, :c=>3} 1.9.3p125 :003 > h.except(:a) => {:b=>2, :c=>3} 1.9.3p125 :004 > h.slice(:a) => {:a=>1}

except utiliza un enfoque de lista negra, por lo que elimina todas las claves enumeradas como argumentos, mientras que slice usa un enfoque de lista blanca, por lo que elimina todas las claves que no figuran como argumentos. También existe la versión de bang de aquellos métodos ( except! Y slice! ) Que modifican el hash dado pero su valor de retorno es diferente, ambos devuelven un hash. Representa las claves eliminadas para slice! y las llaves que se guardan para la except! :

1.9.3p125 :011 > {:a => 1, :b => 2, :c => 3}.except!(:a) => {:b=>2, :c=>3} 1.9.3p125 :012 > {:a => 1, :b => 2, :c => 3}.slice!(:a) => {:b=>2, :c=>3}


Puedes usar except! de la facets joya:

>> require ''facets'' # or require ''facets/hash/except'' => true >> {:a => 1, :b => 2}.except(:a) => {:b=>2}

El hash original no cambia.

EDITAR: como dice Russel, facetas tiene algunos problemas ocultos y no es completamente compatible con API con ActiveSupport. Por otro lado, ActiveSupport no es tan completo como las facetas. Al final, usaría AS y dejaría los casos de borde en su código.


Si desea usar Ruby puro (sin Rails), no quiera crear métodos de extensión (quizás necesite esto solo en uno o dos lugares y no quiera contaminar el espacio de nombres con toneladas de métodos) y no quiera Editar hash en su lugar (es decir, eres fanático de la programación funcional como yo), puedes ''seleccionar'':

>> x = {:a => 1, :b => 2, :c => 3} => {:a=>1, :b=>2, :c=>3} >> x.select{|x| x != :a} => {:b=>2, :c=>3} >> x.select{|x| ![:a, :b].include?(x)} => {:c=>3} >> x => {:a=>1, :b=>2, :c=>3}



en rubí puro:

{:a => 1, :b => 2}.tap{|x| x.delete(:a)} # => {:b=>2}


Rails tiene un except / except! Método que devuelve el hash con esas claves eliminadas. Si ya está usando Rails, no tiene sentido crear su propia versión de esto.

class Hash # Returns a hash that includes everything but the given keys. # hash = { a: true, b: false, c: nil} # hash.except(:c) # => { a: true, b: false} # hash # => { a: true, b: false, c: nil} # # This is useful for limiting a set of parameters to everything but a few known toggles: # @person.update(params[:person].except(:admin)) def except(*keys) dup.except!(*keys) end # Replaces the hash without the given keys. # hash = { a: true, b: false, c: nil} # hash.except!(:c) # => { a: true, b: false} # hash # => { a: true, b: false } def except!(*keys) keys.each { |key| delete(key) } self end end


#in lib/core_extensions.rb class Hash #pass single or array of keys, which will be removed, returning the remaining hash def remove!(*keys) keys.each{|key| self.delete(key) } self end #non-destructive version def remove(*keys) self.dup.remove!(*keys) end end #in config/initializers/app_environment.rb (or anywhere in config/initializers) require ''core_extensions''

He configurado esto para que .remove devuelva una copia del hash con las claves eliminadas, ¡mientras elimina! modifica el hash mismo. Esto está en consonancia con las convenciones de rubí. por ejemplo, desde la consola

>> hash = {:a => 1, :b => 2} => {:b=>2, :a=>1} >> hash.remove(:a) => {:b=>2} >> hash => {:b=>2, :a=>1} >> hash.remove!(:a) => {:b=>2} >> hash => {:b=>2} >> hash.remove!(:a, :b) => {}