2010-10-28 4 views

Répondre

1

Je suppose que vous voulez changer le hachage keys sans changer les valeurs:

hash = {"nr"=>"123", "name"=>"Herrmann Hofreiter", "pferd"=>"010 000 777", "land"=>"hight land"} 
header = ["nr", "name", "hourse", "land"] 
new_hash = header.zip(hash.values).to_h 

résultat: { "nr" => "123", " name "=>" Herrmann Hofreiter "," hourse "=>" 010 000 777 "," land "=>" haute terre "}

+0

Un moment de promotion personnelle but, mais juste pour le laisser ici: si quelque chose d'un peu plus complexe est nécessaire (comme sélectionner des touches particulières en même temps ou contraindre des types de valeurs et ainsi de suite), je mets une minuscule lib: https : //github.com/smileart/hash_remapper – smileart

3

La solution exacte dépendra du format que vous avez les nouvelles clés (ou si vous pouvez déduire la nouvelle clé de l'ancienne clé.)

En supposant que vous avez un hachage h dont les clés que vous souhaitez modifier et un hachage new_keys qui mappe les clés actuelles aux nouvelles clés que vous pourriez faire:

h.keys.each do |key| 
    h[new_keys[key]] = h[key] # add entry for new key 
    k.delete(key)    # remove old key 
end 
+1

Ceci supprimera une valeur pour' key' quand ' new_keys' arrive accidentellement à retourner 'key' lui-même pour quelque' key'. La réponse de barbolos à cette question: http://stackoverflow.com/questions/4137824 surmonte ce problème. – sawa

+2

au lieu de cela, vous pouvez utiliser 'h.keys.each {| key | h [new_keys [clé]] = h.delete (touche)} ' – Selvamani

+0

@Selvamani, voir ma réponse, et créer une réponse à partir de votre commentaire. –

73

en supposant que vous avez une Hash qui associe les anciennes clés de nouvelles clés, vous pouvez faire quelque chose comme

hsh.map {|k, v| [key_map[k], v] }.to_h 
+4

Vous êtes l'homme! Votre hash est totalement génial! Merci encore pour ce petit bijou!:) – CalebHC

+1

Il suppose également que vous avez 'key_map' défini comme un hachage de paires clé/valeur où la clé est l'ancienne clé et la valeur est la nouvelle clé permutée. –

-1

Si vous vous inquiétez également sur la performance, c'est plus rapide:

hsh.keys.each { |k| hsh[ key_map[k] ] = hsh.delete(k) if key_map[k] } 

Vous ne créez pas une nouvelle Hash et vous renommer uniquement les clés nécessaires. Cela vous donne de meilleures performances.

Vous pouvez trouver plus de détails dans "How to elegantly rename all keys in a hash in Ruby?"

+0

Cela casse si' key_map [k] 'est nul . –

3

Une autre façon de le faire est:

hash = { 
    'foo' => 1, 
    'bar' => 2 
} 

new_keys = { 
    'foo' => 'foozle', 
    'bar' => 'barzle' 
} 

new_keys.values.zip(hash.values_at(*new_keys.keys)).to_h 
# => {"foozle"=>1, "barzle"=>2} 

Décomposant:

new_keys 
.values # => ["foozle", "barzle"] 
.zip(
    hash.values_at(*new_keys.keys) # => [1, 2] 
) # => [["foozle", 1], ["barzle", 2]] 
.to_h 
# => {"foozle"=>1, "barzle"=>2} 

Il est temps de référence ..

Bien que j'aime la simplicité de la réponse de Jörn, je n'étais pas sûr qu'il était aussi vite qu'il devrait être, j'ai vu le commentaire de selvamani:

require 'fruity' 

HASH = { 
    'foo' => 1, 
    'bar' => 2 
} 

NEW_KEYS = { 
    'foo' => 'foozle', 
    'bar' => 'barzle' 
} 

compare do 
    mittag { HASH.dup.map {|k, v| [NEW_KEYS[k], v] }.to_h } 
    ttm  { h = HASH.dup; NEW_KEYS.values.zip(h.values_at(*NEW_KEYS.keys)).to_h } 
    selvamani { h = HASH.dup; h.keys.each { |key| h[NEW_KEYS[key]] = h.delete(key)}; h } 
end 

# >> Running each test 2048 times. Test will take about 1 second. 
# >> selvamani is faster than ttm by 39.99999999999999% ± 10.0% 
# >> ttm is faster than mittag by 10.000000000000009% ± 10.0% 

Ceux-ci sont en cours d'exécution très proche vitesse ensemble sage, de sorte que toute fera, mais 39% rapporte au fil du temps alors considérez cela. Quelques réponses n'ont pas été incluses parce qu'il y a des failles potentielles dans lesquelles elles renverraient de mauvais résultats.

0
h = { 'foo'=>1, 'bar'=>2 } 
key_map = { 'foo'=>'foozle', 'bar'=>'barzle' } 

h.each_with_object({}) { |(k,v),g| g[key_map[k]]=v } 
    #=> {"foozle"=>1, "barzle"=>2} 

ou

h.reduce({}) { |g,(k,v)| g.merge(key_map[k]=>v) } 
    #=> {"foozle"=>1, "barzle"=>2} 
+0

Je pense que l'appel à la fusion pour chaque touche sera relativement lent – Josh

+0

@Josh, vous avez raison. J'ai re-couru le benchmark de theTinMan avec mes deux méthodes ajoutées et obtenu les résultats suivants: "selvamani est plus rapide que ttm de 19.99% ± 1.0%, ttm est similaire à caryewo (utilise' each_with_object'), caryewo est similaire à mittag; est plus rapide que caryred (utilise 'réduire') de 70,0% ± 10,0%". –

Questions connexes