Wie bekomme ich eine bestimmte Ausgabe, die einen Hash in Ruby iteriert?

218

Ich möchte eine bestimmte Ausgabe erhalten, die einen Ruby Hash iteriert.

Dies ist der Hash, über den ich iterieren möchte:

hash = {
  1 => ['a', 'b'], 
  2 => ['c'], 
  3 => ['d', 'e', 'f', 'g'], 
  4 => ['h']
}

Dies ist die Ausgabe, die ich erhalten möchte:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

Wie kann ich in Ruby eine solche Ausgabe mit meinem Hash erhalten?

sts
quelle
3
Wenn Sie einen Hash iterieren und erwarten, dass er bestellt wird, müssen Sie wahrscheinlich einen anderen Sammlungstyp verwenden
Allen Rice
Kann ich die Hash-Werte als Optionsfeld übergeben?
M.
Ich übergebe den Hash als Optionsfeldoption. Aber für die erste Option erhalte ich ein Optionsfeld, für andere Werte erhalte ich es nicht.
M.
1
@ Allen: Hashes sind in Ruby 1.9 bestellt. Rails bietet auch einen OrderedHash (der nur sparsam verwendet wird), wenn Sie Ruby <1.9 verwenden. Siehe culann.com/2008/01/rails-goodies-activesupportorderedhash
James A. Rosen

Antworten:

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

In Bezug auf die Reihenfolge sollte ich hinzufügen, dass in 1.8 die Elemente in zufälliger Reihenfolge iteriert werden (also tatsächlich in einer Reihenfolge, die durch die Hashing-Funktion von Fixnum definiert ist), während sie in 1.9 in der Reihenfolge des Literal iteriert werden.

sepp2k
quelle
1
Was ist, wenn der Schlüssel nirgendwo verwendet wird? . Müssen wir einen ?Schlüssel ersetzen? Beispiel: |?, array|Ist diese Syntax gültig?
Huzefa Biyawarwala
1
@huzefabiyawarwala Nein, ?ist kein gültiger Variablenname in Ruby. Sie können verwendet werden _, aber Sie nicht brauchen , um.
sepp2k
2
@huzefabiyawarwala Ja, Sie können schreiben|_, v|
sepp2k
1
Was verwendet ein Variablennamen-Array anstelle von v oder value?
Jrhicks
1
@jrhicks Weil das OP einen Hash hat, dessen Werte Arrays sind.
Radon Rosborough
85

Der einfachste Weg, einen Hash zu durchlaufen, ist folgender:

hash.each do |key, value|
  puts key
  puts value
end
Tomascharad
quelle
Ja, das macht Sinn. Warum hat die Antwort von @ sepp2k ein # {} auf dem Schlüssel?
committedandroider
Vergiss es. Ich sah , dass es für String - Interpolation war
committedandroider
48
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end
erik
quelle
18

Wenn Sie sort für einen Hash aufrufen, wird dieser in verschachtelte Arrays konvertiert und anschließend nach Schlüssel sortiert. Sie benötigen also nur Folgendes:

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

Und wenn Sie den Teil "----" nicht wirklich benötigen, kann es nur sein:

puts h.sort
Glenn McDonald
quelle
Die Hash-Schlüssel sind Zahlen, daher löst '[k + "----"]' einen TypeError aus (String kann nicht in Fixnum gezwungen werden). Sie benötigen '[k.to_s + "----"]'
Glenn Jackman
Wahr genug. Ich hatte Briefe in meiner Testversion. Behoben, mit dem noch besseren "# {k} ----".
Glenn McDonald
10

Meine einzeilige Lösung:

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

Ich denke, es ist ziemlich einfach zu lesen.

Elie Teyssedou
quelle
1

Sie können auch verfeinern, Hash::each damit die rekursive Aufzählung unterstützt wird. Hier ist meine Version von Hash::each( Hash::each_pair) mit Block- und Enumerator- Unterstützung:

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

Hier sind Verwendungsbeispiele von Hash::eachmit und ohne recursiveFahne:

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

Hier ist ein Beispiel aus der Frage selbst:

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

Schauen Sie sich auch meine rekursive Version von Hash::merge( Hash::merge!) hier an .

MOPO3OB
quelle