2009-08-04 22 views
184

que tienen un hash de esta manera:¿Cómo iterar sobre un hash en Ruby?

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

Como puedo repetir con el fin de obtener una salida como esta:

1----- 

a 

b 

2----- 

c 

3----- 

a 

d 

f 

g 
+3

Si estamos iterando un hash y esperando que se puede pedir, es probable que tenga que utilizar algún otro tipo de colección –

+0

puedo pasar los valores hash opción de botón de radio como ?? – sts

+0

estoy pasando el hash botón de opción .. como, pero por la primera opción estoy recibiendo botón de radio, para otros valores no estoy recibiendo. – sts

Respuesta

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

cuanto a orden debo añadir, que en 1.8 los artículos será iterado en orden aleatorio (bueno, de hecho en un orden definido por la función hash de Fixnum), mientras que en 1.9 se repetirá en el orden del literal.

+1

aquí lo que si la llave no se utiliza en cualquier lugar? . ¿Necesitamos poner un '?' en lugar de la tecla? ex: '|?, array |' ¿es esta sintaxis válida? –

+0

@huzefabiyawarwala No, '?' No es un nombre de variable válido en Ruby. Puede usar '_', pero no * necesita * para. – sepp2k

+0

lo que quise decir es si usamos '| k, v |' para iterar sobre un hash, pero no usamos 'k' en nuestra implementación lógica dentro de nuestro ciclo, así que ¿hay alguna manera de que podamos escribir así' | _, v | '? –

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

Calling especie en un hash convierte en matrices anidadas y luego los ordena por la clave, por lo que todo lo que necesita es la siguiente:

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

Y si en realidad no necesita el "- -" parte, puede ser simplemente:

puts h.sort 
+0

Las teclas hash son números, por lo que '[k + "----"]' genera un TypeError (String no se puede forzar en Fixnum).Necesitas '[k.to_s + "----"]' –

+0

Cierto. Tenía cartas en mi versión de prueba. Corregido, usando el mejor "# {k} ----". –

+0

Definitivamente la mejor respuesta de las actualmente enumeradas. –

67

La forma más básica para iterar sobre un hash es el siguiente:

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

También puede refinarHash::each por lo que admitirá recursivo enumeración. Aquí es mi versión de Hash::each (Hash::each_pair) con bloque y empadronador de apoyo:

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 

Éstos son el uso ejemplos de Hash::each con y sin recursive bandera:

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 

Aquí es ejemplo de la pregunta en sí misma:

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"] 

También eche un vistazo a mi versión recursiva de Hash::merge (Hash::merge!) here.