web-dev-qa-db-fra.com

Comment supprimer une clé du hachage et récupérer le hachage restant dans Ruby / Rails?

Pour ajouter une nouvelle paire à Hash I do:

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

Existe-t-il une méthode similaire pour supprimer une clé de hachage?

Cela marche:

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

mais je m'attendrais à avoir quelque chose comme:

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

Il est important que la valeur renvoyée soit le hachage restant afin que je puisse faire des choses comme:

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

dans une ligne.

514
Misha Moroshko

Rails a une méthode except/except! qui renvoie le hachage avec ces clés supprimées. Si vous utilisez déjà Rails, il ne sert à rien de créer votre propre version.

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
692
Peter Brown

Oneliner uni 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} 

Tap la méthode retourne toujours l'objet sur lequel est invoqué ...

Sinon, si vous avez requis active_support/core_ext/hash (qui est automatiquement requis dans chaque application Rails], vous pouvez utiliser l'une des méthodes suivantes, en fonction de 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} 

excepté utilise une approche de liste noire, de sorte qu'il supprime toutes les clés répertoriées comme arguments, tandis que slice utilise une approche de liste blanche, de sorte qu'il supprime toutes les clés non répertoriées comme arguments. Il existe également la version bang de ces méthodes (except! et slice!) qui modifient le hachage donné mais dont la valeur de retour est différente, et qui retournent un hachage. Il représente les clés supprimées pour slice! et les clés conservées pour le 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} 
192
Fabio

Pourquoi ne pas simplement utiliser:

hash.delete(key)
165
dbryson

Il existe de nombreuses façons de supprimer une clé d'un hachage et d'obtenir le hachage restant en Ruby.

  1. .slice => Il retournera les clés sélectionnées et ne les supprimera pas du hachage d'origine. Utilisez slice! si vous souhaitez supprimer définitivement les clés, sinon utilisez la méthode simple slice.

    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 => Il supprimera les clés sélectionnées du hachage d'origine (il ne peut en accepter qu'une seule et pas plus d'une).

    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 => Il retournera les clés restantes mais ne supprimera rien du hachage d'origine. Utilisez except! si vous souhaitez supprimer définitivement les clés, sinon utilisez la méthode simple except.

    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 => Si vous devez supprimer une clé basée sur une valeur. Cela supprimera évidemment les clés correspondantes du hachage d'origine.

    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} 
    
  5. .compact => Il est utilisé pour supprimer toutes les valeurs nil du hachage. Utilisez compact! si vous souhaitez supprimer définitivement les valeurs nil, sinon utilisez la méthode simple compact.

    2.2.2 :119 > hash = {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil}
     => {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil} 
    2.2.2 :120 > hash.compact
     => {"one"=>1, "two"=>2, "three"=>3}
    

Résultats basés sur Ruby 2.2.2.

67
techdreams

Si vous voulez utiliser pure Ruby (sans Rails), ne voulez pas créer de méthodes d'extension (vous n'avez peut-être besoin de cela que dans un ou deux endroits et vous ne voulez pas polluer l'espace de noms avec des tonnes de méthodes) et vous ne voulez pas éditer le hachage en place (vous êtes fan de la programmation fonctionnelle comme moi), vous pouvez "sélectionner":

>> 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}
37
Yura Taras
#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 configuré cela pour que .remove retourne une copie du hachage avec les clés retirées, en supprimant! modifie le hash lui-même. Ceci est conforme aux conventions Ruby. par exemple, depuis 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)
=> {}
31
Max Williams

Vous pouvez utiliser except! à partir du 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 le dit Russel, les facettes ont des problèmes cachés et ne sont pas complètement compatibles avec les API avec ActiveSupport. De l’autre côté, ActiveSupport n’est pas aussi complet que les facettes. En fin de compte, j'utiliserais AS et laisserais Edge figurer dans votre code.

27
rewritten

Au lieu d'appliquer des correctifs pour les singes ou d'inclure inutilement de grandes bibliothèques, vous pouvez utiliser raffinements si vous utilisez 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

Vous pouvez utiliser cette fonctionnalité sans affecter d'autres parties de votre programme, ni avoir à inclure de grandes bibliothèques externes.

class FabulousCode
  using HashExtensions

  def incredible_stuff
    delightful_hash.except(:not_fabulous_key)
  end
end
19
Mohamad

en rubis pur:

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

Voir Ruby on Rails: Supprimer plusieurs clés de hachage

hash.delete_if{ |k,| keys_to_delete.include? k }
11
Nakilon

C'était génial si delete renvoie la paire de suppression du hachage. Je fais ça:

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

C'est une façon de faire une ligne, mais ce n'est pas très lisible. Recommandez d'utiliser deux lignes à la place.

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

Plusieurs façons de supprimer Key in Hash. vous pouvez utiliser n'importe quelle méthode ci-dessous

hash = {a: 1, b: 2, c: 3}
hash.except!(:a) # Will remove *a* and return HASH
hash # Output :- {b: 2, c: 3}

hash = {a: 1, b: 2, c: 3}
hash.delete(:a) # will remove *a* and return 1 if *a* not present than return nil

Il y a tant de façons, vous pouvez regarder sur Ruby doc de Hash ici .

Je vous remercie

1
Ketan Mangukiya