2009-08-04 12 views
184

mam hash takiego:Jak iterować nad hash w Ruby?

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

Jak mogę iterację go w celu uzyskania wyjścia tak:

1----- 

a 

b 

2----- 

c 

3----- 

a 

d 

f 

g 
+3

Jeśli przeprowadzasz iterację hash i oczekujesz, że zostanie ona zamówiona, prawdopodobnie będziesz musiał użyć innego typu kolekcji: –

+0

Czy mogę przekazać wartości mieszania jako opcję przycisku opcji? – sts

+0

Przekazuję skrót, jako opcję opcji .. , ale dla pierwszej opcji otrzymuję przycisk opcji, ponieważ inne wartości nie są dostępne. – sts

Odpowiedz

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

celu Dodam chodzi, że w 1,8 przedmiotów będzie iterowane w kolejności losowej (cóż, faktycznie w kolejności zdefiniowanej przez funkcję haszującą Fixnuma), podczas gdy w wersji 1.9 będzie iterowane w kolejności literału.

+1

tutaj, co jeśli klucz nie jest używany w dowolnym miejscu? . czy musimy wstawić '?' zamiast klucza? Przykład: '|?, tablica |' to jest ta poprawna składnia? –

+0

@huzefabiyawarwala Nie, '?' Nie jest poprawną nazwą zmiennej w Ruby. Możesz użyć '_', ale nie * potrzebujesz *. – sepp2k

+0

co miałem na myśli, jeśli użyjemy '| k, v |' do iteracji na haszyszu, ale nie używamy 'k' w naszej implementacji logicznej w naszej pętli, więc czy jest jakiś sposób, abyśmy mogli napisać w ten sposób' | _, v | '? –

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

Wywołanie rodzaju na hash zamienia go na zagnieżdżonych tablic, a następnie sortuje je według klucza, więc wszystko, czego potrzebujesz to:

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

A jeśli nie faktycznie potrzebne „- -”część, może to być po prostu:

puts h.sort 
+0

Kluczami skrótu są liczby, więc "[k +" ---- "]" podnosi TypeError (String nie może być wymuszony na Fixnum).Potrzebujesz "[k.to_s +" ---- "] ' –

+0

To prawda. Miałem listy w mojej wersji testowej. Naprawiono, używając jeszcze lepszego "# {k} ----". –

+0

Zdecydowanie najlepsza odpowiedź tych, którzy są obecnie na liście. –

67

Najprostszym sposobem iteracyjne nad mieszania jest następujący:

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

Możesz również poprawić wartość: , aby poprawić rekursywną wyliczanie. Oto moja wersja Hash::each (Hash::each_pair) z bloku i wyliczający wsparcia:

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 

Oto Wykorzystanie przykładów z Hash::each i bez recursive flag

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 

Oto przykład z samego pytania:

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

Proszę również spojrzeć na moją rekursywną wersję Hash::merge (Hash::merge!) here.