253 votos

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

Para agregar un nuevo par en Hash que hago:

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

¿Hay una manera similar al eliminar una clave de hash?

Esto funciona:

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

pero yo esperaría a tener algo como:

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

Es importante que el valor de vuelta estará el hash restante, por lo que podría hacer cosas como:

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

en una línea.

387voto

Beerlington Puntos 25012

Rails tiene una excepción / salvo! método que devuelve el hash con esas llaves retiradas. Si usted ya está usando Rails, no tiene sentido en la creación de su propia versión de este.

 class Hash
  # Return a hash that includes everything but the given keys. This is useful for
  # limiting a set of parameters to everything but a few known toggles:
  #
  #   @person.update_attributes(params[:person].except(:admin))
  #
  # If the receiver responds to +convert_key+, the method is called on each of the
  # arguments. This allows +except+ to play nice with hashes with indifferent access
  # for instance:
  #
  #   {:a => 1}.with_indifferent_access.except(:a)  # => {}
  #   {:a => 1}.with_indifferent_access.except("a") # => {}
  #
  def except(*keys)
    dup.except!(*keys)
  end

  # Replaces the hash without the given keys.
  def except!(*keys)
    keys.each { |key| delete(key) }
    self
  end
end
 

110voto

Fabio Puntos 8145

Oneliner llanura de ruby, que funciona sólo 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} 

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

De lo contrario, si usted solicita active_support/core_ext/hash (que es automáticamente necesaria en cada aplicación Rails), se puede utilizar uno de los métodos siguientes dependiendo de 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} 

excepto que utiliza una lista negra de enfoque, por lo que elimina todas las teclas que figuran como argumentos, mientras que rebanada utiliza una lista blanca de enfoque, por lo que elimina todas las claves que no aparecen como argumentos. También existe la explosión de la versión de los método (except! y slice!) que modifican el dado de hash, pero su valor de retorno es distinto ambas devuelven un valor hash. Representa la quita claves para slice! y las teclas que se mantienen 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} 

85voto

dbryson Puntos 2945

¿Por qué no sólo tiene que utilizar:

 hash.delete(key)
 

25voto

Max Williams Puntos 10129
 #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 puesto esto para que .Extraer devuelve una copia del hash con las teclas retiradas, mientras que quitar! modifica la propia hash. 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)
=> {}
 

19voto

rewritten Puntos 7430

Usted puede 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.

EDIT: como dice Russel, facetas tiene algunos problemas ocultos y no es totalmente compatible con la API-ActiveSupport. Por otro lado ActiveSupport no es tan completa como facetas. En la final, que haría uso de AS y dejar que los casos extremos en el código.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: