2009-08-04 7 views
184

J'ai un hachage comme ceci:Comment itérer sur un hachage en Ruby?

{ 
1=>["a", "b"], 
2=>["c"], 
3=>["a", "d", "f", "g"], 
4=>["q"] 
} 

Comment puis-je itérer ce afin d'obtenir une sortie comme ceci:

1----- 

a 

b 

2----- 

c 

3----- 

a 

d 

f 

g 
+3

Si vous itérez un hachage et attendez qu'il soit commandé, vous devrez probablement utiliser un autre type de collection –

+0

Puis-je transmettre les valeurs de hachage comme option de bouton radio? – sts

+0

passer le hachage comme option de bouton radio .. mais pour la première option je reçois le bouton radio, pour les autres valeurs je ne comprends pas. – sts

Répondre

280
hash.each do |key, array| 
    puts "#{key}-----" 
    puts array 
end 

En ce qui concerne l'ordre, je dois ajouter que dans 1.8 les éléments sera itéré dans un ordre aléatoire (enfin, dans un ordre défini par la fonction de hachage de Fixnum), alors qu'en 1.9 il sera itéré dans l'ordre du littéral.

+1

ici et si la clé n'est pas utilisée n'importe où? . avons-nous besoin de mettre un «?» à la place de la clé? ex: '| ?, array |' est cette syntaxe valide? –

+0

@huzefabiyawarwala Non, '?' N'est pas un nom de variable valide dans Ruby. Vous pouvez utiliser '_', mais vous n'avez pas besoin de *. – sepp2k

+0

ce que je voulais dire, c'était si nous utilisions '| k, v |' pour itérer sur un hash, mais nous n'utilisons pas k dans notre implémentation logique dans notre boucle, donc nous pouvons écrire comme ceci '| _, v | '? –

47
hash.keys.sort.each do |key| 
    puts "#{key}-----" 
    hash[key].each { |val| puts val } 
end 
16

appel tri sur un hachage convertit en tableaux imbriqués, puis les trie par clé, donc tout ce que vous avez besoin est ceci:

puts h.sort.map {|k,v| ["#{k}----"] + v} 

Et si vous n'avez pas besoin en fait le « - - » part, il peut être juste:

puts h.sort 
+0

Les clés de hachage sont des nombres, ainsi '[k + "----"]' déclenche une erreur de type (String ne peut pas être forcé dans Fixnum).Vous avez besoin de '[k.to_s + "----"]' –

+0

Assez vrai. J'avais des lettres dans ma version d'essai. Correction, en utilisant le meilleur "# {k} ----". –

+0

Certainement la meilleure réponse de ceux actuellement listés. –

67

La façon la plus simple de itérer sur une table de hachage est la suivante:

hash.each do |key, value| 
    puts key 
    puts value 
end 
0

Vous pouvez également affinerHash::each de sorte qu'il prendra en charge recursive énumération. Voici ma version de Hash::each (Hash::each_pair) avec bloc et recenseur soutien:

module HashRecursive 
    refine Hash do 
     def each(recursive=false, &block) 
      if recursive 
       Enumerator.new do |yielder| 
        self.map do |key, value| 
         value.each(recursive=true).map{ |key_next, value_next| yielder << [[key, key_next].flatten, value_next] } if value.is_a?(Hash) 
         yielder << [[key], value] 
        end 
       end.entries.each(&block) 
      else 
       super(&block) 
      end 
     end 
     alias_method(:each_pair, :each) 
    end 
end 

using HashRecursive 

Voici utilisation exemples de Hash::each avec et sans recursive drapeau:

hash = { 
    :a => { 
     :b => { 
      :c => 1, 
      :d => [2, 3, 4] 
     }, 
     :e => 5 
    }, 
    :f => 6 
} 

p hash.each, hash.each {}, hash.each.size 
# #<Enumerator: {:a=>{:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}, :f=>6}:each> 
# {:a=>{:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}, :f=>6} 
# 2 

p hash.each(true), hash.each(true) {}, hash.each(true).size 
# #<Enumerator: [[[:a, :b, :c], 1], [[:a, :b, :d], [2, 3, 4]], [[:a, :b], {:c=>1, :d=>[2, 3, 4]}], [[:a, :e], 5], [[:a], {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}], [[:f], 6]]:each> 
# [[[:a, :b, :c], 1], [[:a, :b, :d], [2, 3, 4]], [[:a, :b], {:c=>1, :d=>[2, 3, 4]}], [[:a, :e], 5], [[:a], {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5}], [[:f], 6]] 
# 6 

hash.each do |key, value| 
    puts "#{key} => #{value}" 
end 
# a => {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5} 
# f => 6 

hash.each(true) do |key, value| 
    puts "#{key} => #{value}" 
end 
# [:a, :b, :c] => 1 
# [:a, :b, :d] => [2, 3, 4] 
# [:a, :b] => {:c=>1, :d=>[2, 3, 4]} 
# [:a, :e] => 5 
# [:a] => {:b=>{:c=>1, :d=>[2, 3, 4]}, :e=>5} 
# [:f] => 6 

hash.each_pair(recursive=true) do |key, value| 
    puts "#{key} => #{value}" unless value.is_a?(Hash) 
end 
# [:a, :b, :c] => 1 
# [:a, :b, :d] => [2, 3, 4] 
# [:a, :e] => 5 
# [:f] => 6 

Voici par exemple de la question elle-même:

hash = { 
    1 => ["a", "b"], 
    2 => ["c"], 
    3 => ["a", "d", "f", "g"], 
    4 => ["q"] 
} 

hash.each(recursive=false) do |key, value| 
    puts "#{key} => #{value}" 
end 
# 1 => ["a", "b"] 
# 2 => ["c"] 
# 3 => ["a", "d", "f", "g"] 
# 4 => ["q"] 

Jetez également un oeil à ma version récursive de Hash::merge (Hash::merge!) here.

Questions connexes