2009-08-04 22 views
184

Ho un hash come questo:Come eseguire iterazioni su un hash in Ruby?

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

Come posso iterare al fine di ottenere l'output simile a questo:

1----- 

a 

b 

2----- 

c 

3----- 

a 

d 

f 

g 
+3

Se si sta eseguendo l'iterazione di un hash e si aspetta che venga ordinato, è probabilmente necessario utilizzare qualche altro tipo di raccolta –

+0

posso passare i valori dell'hash come opzione del pulsante di opzione ?? – sts

+0

sto passando l'hash come opzione pulsante radio .. ma per la prima opzione sto ottenendo il pulsante radio, per altri valori non lo ottengo. – sts

risposta

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

Per quanto riguarda la fine devo aggiungere, che in 1.8 gli articoli sarà iterato in ordine casuale (beh, in realtà in un ordine definito dalla funzione di hashing di Fixnum), mentre in 1.9 verrà iterato nell'ordine del letterale.

+1

cosa succede se la chiave non viene utilizzata da nessuna parte? . abbiamo bisogno di mettere un '?' al posto della chiave? ex: '| ?, array |' è questa sintassi valida? –

+0

@huzefabiyawarwala No, '?' Non è un nome di variabile valido in Ruby. Puoi usare '_', ma non * hai * bisogno di. – sepp2k

+0

quello che intendevo era se usassimo '| k, v |' per iterare su un hash, ma non usiamo 'k' nella nostra implementazione logica all'interno del nostro ciclo, quindi c'è un modo in cui possiamo scrivere in questo modo' | _, v | '? –

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

Calling sorta su un hash converte in array nidificati e poi le ordina a chiave, quindi tutto ciò che serve è questo:

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

E se non lo fai in realtà bisogno della "- -" parte, può essere solo:

puts h.sort 
+0

Le chiavi di hash sono numeri, quindi '[k + "----"]' genera un errore TypeE (la stringa non può essere forzata in Fixnum).Hai bisogno di '[k.to_s + "----"]' –

+0

Abbastanza vero. Ho avuto delle lettere nella mia versione di prova. Risolto, usando ancora meglio "# {k} ----". –

+0

Definitivamente la migliore risposta di quelli attualmente elencati. –

67

Il modo più semplice per iterare su un hash è la seguente:

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

È inoltre possibile perfezionareHash::each in modo da supportare l'enumerazione ricorsiva. Ecco la mia versione di Hash::each (Hash::each_pair) con blocco e enumeratore supporto:

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 

Ecco utilizzo esempi di Hash::each con e senza recursive bandiera:

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 

Ecco esempio dalla domanda stessa:

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

Inoltre, dare un'occhiata alla mia versione ricorsiva di Hash::merge (Hash::merge!) here.

Problemi correlati