ruby-on-rails - array - ruby tableau 2 dimensions




Comment supprimer une clé de Hash et obtenir le hachage restant dans Ruby/Rails? (8)

Pour ajouter une nouvelle paire à Hash je fais:

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

Existe-t-il une manière similaire de supprimer une clé de Hash?

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 retournée soit le hash restant, donc je pourrais faire des choses comme:

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

en une ligne.


Au lieu de faire des correctifs de singe ou d'inclure inutilement de grandes bibliothèques, vous pouvez utiliser des améliorations 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, ou avoir à inclure de grandes bibliothèques externes.

class FabulousCode
  using HashExtensions

  def incredible_stuff
    delightful_hash.except(:not_fabulous_key)
  end
end

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

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

Il y a plusieurs façons de retirer une clé d'un hachage et d'obtenir le hachage restant dans Ruby.

  1. .slice => Il retournera les clés sélectionnées et ne les supprimera pas du hash d'origine

    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 va supprimer les clés sélectionnées du hash d'origine (il ne peut accepter qu'une seule clé 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 hash d'origine

    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 => Au cas où vous devriez enlever une clé basée sur une valeur. Il va évidemment supprimer 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} 
    

Résultats basés sur Ruby 2.2.2.


Oneliner plaine rubis, cela fonctionne uniquement 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 méthode Tap retourne toujours l'objet sur lequel est invoqué ...

Sinon, si vous avez besoin de l' active_support/core_ext/hash (qui est automatiquement requise 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, donc 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 qui ne sont pas répertoriées comme arguments. Il existe aussi la version bang de ces méthodes ( except! Et slice! ) Qui modifient le hachage donné mais leur valeur de retour est différente les deux retournent un hachage. Il représente les clés supprimées pour la slice! et les clés 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} 

Si vous voulez utiliser du Ruby pur (sans Rails), vous ne voulez pas créer de méthodes d'extension (peut-être vous n'en avez besoin qu'à un ou deux endroits et ne voulez pas polluer l'espace de noms avec des tonnes de méthodes) et vous ne voulez pas modifier le hachage en place (c'est-à-dire, 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}


en pur Ruby:

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

Rails a un sauf / sauf! méthode qui renvoie le hachage avec ces clés supprimées. Si vous utilisez déjà Rails, il n'y a aucun sens à créer votre propre version de cela.

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




ruby-hash