101 votes

Comment renommer avec élégance toutes les clés d'un hachage en Ruby?

J'ai un hash de rubis:

 ages = { "Bruce" => 32,
         "Clark" => 28
       }
 

En supposant que j’ai un autre hachage de noms de remplacement, existe-t-il un moyen élégant de renommer toutes les clés afin d’obtenir les informations suivantes:

 ages = { "Bruce Wayne" => 32,
         "Clark Kent" => 28
       }
 

196voto

Jörg W Mittag Points 153275
ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}

Hash[ages.map {|k, v| [mappings[k], v] }]

53voto

barbolo Points 682

J'ai aimé la réponse de Jörg W Mittag , mais je pense qu'elle peut être améliorée. Si vous souhaitez renommer les clés de votre hachage actuel et ne pas créer un nouveau hachage avec les clés renommées, l'extrait de code suivant fait exactement cela:

 ages = { "Bruce" => 32, "Clark" => 28 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}

ages.keys.each { |k| ages[ mappings[k] ] = ages.delete(k) if mappings[k] }
ages
 

Il y a aussi l'avantage de ne renommer que les clés nécessaires.

8voto

the Tin Man Points 69148

Juste pour voir ce qui était plus rapide:

 require 'fruity'

AGES = { "Bruce" => 32, "Clark" => 28 }
MAPPINGS = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}

def jörg_w_mittag_test(ages, mappings)
  Hash[ages.map {|k, v| [mappings[k], v] }]
end

require 'facets/hash/rekey'
def tyler_rick_test(ages, mappings)
  ages.rekey(mappings)
end

def barbolo_test(ages, mappings)
  ages.keys.each { |k| ages[ mappings[k] ] = ages.delete(k) if mappings[k] }
  ages
end

class Hash
  def tfr_rekey(h)
    dup.tfr_rekey! h
  end

  def tfr_rekey!(h)
    h.each { |k, newk| store(newk, delete(k)) if has_key? k }
    self
  end
end

def tfr_test(ages, mappings)
  ages.tfr_rekey mappings
end

class Hash
  def rename_keys(mapping)
    result = {}
    self.map do |k,v|
      mapped_key = mapping[k] ? mapping[k] : k
      result[mapped_key] = v.kind_of?(Hash) ? v.rename_keys(mapping) : v
      result[mapped_key] = v.collect{ |obj| obj.rename_keys(mapping) if obj.kind_of?(Hash)} if v.kind_of?(Array)
    end
    result
  end
end

def greg_test(ages, mappings)
  ages.rename_keys(mappings)
end

compare do
  jörg_w_mittag { jörg_w_mittag_test(AGES.dup, MAPPINGS.dup) }
  tyler_rick    { tyler_rick_test(AGES.dup, MAPPINGS.dup)    }
  barbolo       { barbolo_test(AGES.dup, MAPPINGS.dup)       }
  greg          { greg_test(AGES.dup, MAPPINGS.dup)          }
end
 

Quelles sorties:

Exécuter chaque test 1024 fois. Le test prendra environ 1 seconde.
barbolo est plus rapide que jörg_w_mittag de 19.999999999999996% ± 10.0%
jörg_w_mittag est plus rapide que greg de 10.000000000000009% ± 10.0%
greg est plus rapide que tyler_rick de 30.000000000000004% ± 10.0%

5voto

Greg Points 1057

I Monkey a corrigé la classe pour gérer les hachages et les tableaux imbriqués

    #  Netsted Hash:
   # 
   #  str_hash = {
   #                "a"  => "a val", 
   #                "b"  => "b val",
   #                "c" => {
   #                          "c1" => "c1 val",
   #                          "c2" => "c2 val"
   #                        }, 
   #                "d"  => "d val",
   #           }
   #           
   # mappings = {
   #              "a" => "apple",
   #              "b" => "boss",
   #              "c" => "cat",
   #              "c1" => "cat 1"
   #           }
   # => {"apple"=>"a val", "boss"=>"b val", "cat"=>{"cat 1"=>"c1 val", "c2"=>"c2 val"}, "d"=>"d val"}
   #
   class Hash
    def rename_keys(mapping)
      result = {}
      self.map do |k,v|
        mapped_key = mapping[k] ? mapping[k] : k
        result[mapped_key] = v.kind_of?(Hash) ? v.rename_keys(mapping) : v
        result[mapped_key] = v.collect{ |obj| obj.rename_keys(mapping) if obj.kind_of?(Hash)} if v.kind_of?(Array)
      end
    result
   end
  end
 

3voto

TFR Points 31

Si le hachage de mappage sera plus petit que le hachage de données, effectuez plutôt une itération sur les mappages. Ceci est utile pour renommer quelques champs dans un grand hachage

 class Hash
  def rekey(h)
    dup.rekey! h
  end

  def rekey!(h)
    h.each { |k, newk| store(newk, delete(k)) if has_key? k }
    self
  end
end

ages = { "Bruce" => 32, "Clark" => 28, "John" => 36 }
mappings = {"Bruce" => "Bruce Wayne", "Clark" => "Clark Kent"}
p ages.rekey! mappings
 

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