642 votes

Comment faire pour supprimer une clé de hachage et obtenir le hachage restant en Ruby/Rails ?

Pour ajouter une nouvelle paire de Hachage je fais:

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

Est-il une manière similaire pour supprimer une clé de Hachage ?

Ceci fonctionne:

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

mais je m'attends à quelque chose comme:

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

Il est important que la valeur de retour sera le reste de hachage, afin que je puisse faire des choses comme:

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

dans une ligne.

831voto

Beerlington Points 25012

Rails a un sauf/sauf! méthode qui retourne la valeur de hachage avec ces clés supprimées. Si vous êtes déjà à l'aide de Rails, il n'y a pas de sens dans la création de votre propre version de ce.

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

237voto

Fabio Points 8145

Oneliner plaine ruby, il ne fonctionne qu'avec 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} 

Appuyez sur la méthode renvoie toujours l'objet sur lequel est invoquée...

Sinon, si vous avez tenus active_support/core_ext/hash (qui est automatiquement requise dans tous les Rails de l'application), vous pouvez utiliser l'une des méthodes suivantes selon vos besoins:

➜  ~  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} 

à l'exception utilise une liste noire de l'approche, de sorte qu'il supprime toutes les clés répertoriés comme args, tandis que la tranche utilise une liste blanche approche, de sorte qu'il supprime toutes les clés qui ne sont pas répertoriés en tant qu'arguments. Il y a aussi le coup de la version de ceux de la méthode (except! et slice!) de modifier la donnée de hachage, mais leur valeur de retour est différente à la fois de rentrer un code de hachage. Il représente l'retiré les clés pour slice! et les touches qui sont conservées pour l' 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} 

235voto

dbryson Points 2945

Pourquoi ne pas simplement utiliser:

hash.delete(key)

30voto

Max Williams Points 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'

J'ai mis cela en place, de sorte que .supprimer renvoie une copie de la table de hachage avec la clé supprimée, tout enlever!! modifie la valeur de hachage lui-même. Ceci est en accord avec ruby conventions. par exemple, à partir de la console

>> 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)
=> {}

27voto

rewritten Points 7430

Vous pouvez utiliser except! de la facets gem:

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

Le hachage d'origine ne change pas.

EDIT: comme Russel dit, facettes a quelques problèmes cachés et n'est pas complètement API compatible avec ActiveSupport. De l'autre côté ActiveSupport est pas aussi complète que les facettes. En fin de compte, je ne l'utiliserais QUE les et laissez-les cas de bord dans votre code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X