web-dev-qa-db-fra.com

Comment remplacer une clé de hachage par une autre clé

J'ai une condition où, je reçois un hash 

  hash = {"_id"=>"4de7140772f8be03da000018", .....}

et je veux que ce hash

  hash = {"id"=>"4de7140772f8be03da000018", ......}

P.S : Je ne sais pas quelles sont les clés du hachage, elles sont aléatoires et comportent un préfixe "_" pour chaque clé et je ne veux pas de caractères de soulignement.

160
Manish Das

Si toutes les clés sont des chaînes et qu'elles ont toutes le préfixe de soulignement, vous pouvez corriger le hachage en place avec ceci:

h.keys.each { |k| h[k[1, k.length - 1]] = h[k]; h.delete(k) }

Le k[1, k.length - 1] bit récupère tous les k sauf le premier caractère. Si vous voulez une copie, alors:

new_h = Hash[h.map { |k, v| [k[1, k.length - 1], v] }]

Ou

new_h = h.inject({ }) { |x, (k,v)| x[k[1, k.length - 1]] = v; x }

Vous pouvez également utiliser sub si vous n'aimez pas la notation k[] pour extraire une sous-chaîne:

h.keys.each { |k| h[k.sub(/\A_/, '')] = h[k]; h.delete(k) }
Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

Et, si seulement certaines des clés ont le préfixe de soulignement:

h.keys.each do |k|
    if(k[0,1] == '_')
        h[k[1, k.length - 1]] = h[k]
        h.delete(k)
    end
end

Des modifications similaires peuvent être apportées à toutes les autres variantes ci-dessus mais ces deux-là:

Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

devrait être d'accord avec les clés qui n'ont pas de préfixe de soulignement sans modifications supplémentaires.

33
mu is too short
hash[:new_key] = hash.delete :old_key
628
gayavat

Rails Hash a une méthode standard pour cela:

hash.transform_keys{ |key| key.to_s.upcase }

http://api.rubyonrails.org/classes/Hash.html#method-i-transform_keys

UPD: méthode Ruby 2.5

116
gayavat

tu peux faire 

hash.inject({}){|option, (k,v) | option["id"] = v if k == "_id"; option}

Cela devrait fonctionner pour votre cas! 

14
Sadiksha Gautam
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }
10
DigitalRoss

Si nous voulons renommer une clé spécifique dans hash, nous pouvons le faire comme suit:
Supposons que mon hash soit my_hash = {'test' => 'Ruby hash demo'}
Je souhaite maintenant remplacer "test" par "message", puis:
my_hash['message'] = my_hash.delete('test')

10
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}
2
maerics

Je suis allé trop loin et est venu avec ce qui suit. Ma motivation derrière ceci était d'ajouter des clés de hachage pour éviter les conflits de portée lors de la fusion de hachages.

Exemples

Étendre la classe de hachage

Ajoute la méthode rekey aux instances de hachage.

# Adds additional methods to Hash
class ::Hash
  # Changes the keys on a hash
  # Takes a block that passes the current key
  # Whatever the block returns becomes the new key
  # If a hash is returned for the key it will merge the current hash 
  # with the returned hash from the block. This allows for nested rekeying.
  def rekey
    self.each_with_object({}) do |(key, value), previous|
      new_key = yield(key, value)
      if new_key.is_a?(Hash)
        previous.merge!(new_key)
      else
        previous[new_key] = value
      end
    end
  end
end

Exemple de préfixe

my_feelings_about_icecreams = {
  Vanilla: 'Delicious',
  chocolate: 'Too Chocolatey',
  strawberry: 'It Is Alright...'
}

my_feelings_about_icecreams.rekey { |key| "#{key}_icecream".to_sym }
# => {:Vanilla_icecream=>"Delicious", :chocolate_icecream=>"Too Chocolatey", :strawberry_icecream=>"It Is Alright..."}

Exemple de garniture

{ _id: 1, ___something_: 'what?!' }.rekey do |key|
  trimmed = key.to_s.tr('_', '')
  trimmed.to_sym
end
# => {:id=>1, :something=>"what?!"}

Aplatissement et ajout d'une "portée"

Si vous passez un hachage à rekey, il fusionnera le hachage, ce qui vous permettra d'aplatir les collections. Cela nous permet d'ajouter une portée à nos clés lors de l'aplatissement d'un hachage afin d'éviter d'écraser une clé lors de la fusion.

people = {
  bob: {
    name: 'Bob',
    toys: [
      { what: 'car', color: 'red' },
      { what: 'ball', color: 'blue' }
    ]
  },
  tom: {
    name: 'Tom',
    toys: [
      { what: 'house', color: 'blue; da ba dee da ba die' },
      { what: 'nerf gun', color: 'metallic' }
    ]
  }
}

people.rekey do |person, person_info|
  person_info.rekey do |key|
    "#{person}_#{key}".to_sym
  end
end

# =>
# {
#   :bob_name=>"Bob",
#   :bob_toys=>[
#     {:what=>"car", :color=>"red"},
#     {:what=>"ball", :color=>"blue"}
#   ],
#   :tom_name=>"Tom",
#   :tom_toys=>[
#     {:what=>"house", :color=>"blue; da ba dee da ba die"},
#     {:what=>"nerf gun", :color=>"metallic"}
#   ]
# }

1
CTS_AE