Jak uzyskać konkretne wyjście iterujące skrót w Ruby?

218

Chcę uzyskać konkretne wyjście iterujące Ruby Hash.

Oto skrót, który chcę powtórzyć:

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

Oto wynik, który chciałbym uzyskać:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

W Ruby, jak mogę uzyskać takie wyjście za pomocą mojego skrótu?

św
źródło
3
Jeśli iterujesz skrót i spodziewasz się, że zostanie zamówiony, prawdopodobnie musisz użyć innego typu kolekcji
Allen Rice
czy mogę przekazać wartości skrótu jako opcję przycisku opcji?
sts
przekazuję skrót jako opcję przycisku opcji ... ale dla pierwszej opcji otrzymuję przycisk opcji, dla innych wartości go nie otrzymuję.
sts
1
@Allen: Hashe są zamawiane w Ruby 1.9. Railsy zapewniają także OrdersHash (którego używa tylko oszczędnie), jeśli używasz Ruby <1.9. Patrz culann.com/2008/01/rails-goodies-activesupportorderedhash
James A. Rosen

Odpowiedzi:

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

Jeśli chodzi o kolejność, powinienem dodać, że w 1.8 elementy będą iterowane w kolejności losowej (cóż, właściwie w kolejności określonej funkcją haszującą Fixnum), natomiast w wersji 1.9 będą iterowane w kolejności dosłownej.

sepp2k
źródło
1
co jeśli klucz nie jest nigdzie używany? . czy musimy umieścić ?klucz zamiast? np .: |?, array|czy to jest poprawna składnia?
huzefa biyawarwala
1
@huzefabiyawarwala Nie, ?nie jest poprawną nazwą zmiennej w Ruby. Możesz użyć _, ale nie musisz .
sepp2k
2
@huzefabiyawarwala Tak, możesz pisać|_, v|
sepp2k
1
do czego używać tablicy nazw zmiennych zamiast v lub wartości?
jrhicks,
1
@jrhicks Ponieważ OP ma skrót, którego wartościami są tablice.
Radon Rosborough
85

Najbardziej podstawowym sposobem iteracji po skrócie jest:

hash.each do |key, value|
  puts key
  puts value
end
tomascharad
źródło
Tak, to ma sens. Dlaczego odpowiedź @ sepp2k ma # {} na klawiszu?
zaangażowanieandroider
Och nieważne. Widziałem, że chodzi o interpolację łańcuchów
popełniono
48
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end
erik
źródło
18

Wywołanie sortowania w haszu przekształca go w zagnieżdżone tablice, 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 tak naprawdę nie potrzebujesz części „----”, może to być po prostu:

puts h.sort
glenn mcdonald
źródło
Kluczami skrótu są cyfry, więc „[k +” ---- ”]” podnosi błąd typu (nie można wymusić ciągu na Fixnum). Potrzebujesz '[k.to_s + "----"]'
glenn jackman
Prawda prawda Miałem litery w mojej wersji testowej. Naprawiono, używając jeszcze lepszego „# {k} ----”.
glenn mcdonald
10

Moje jedno liniowe rozwiązanie:

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

Myślę, że jest dość łatwy do odczytania.

Elie Teyssedou
źródło
1

Możesz także sprecyzować, Hash::each aby obsługiwał wyliczanie rekurencyjne . Oto moja wersja Hash::each( Hash::each_pair) z obsługą bloku i modułu wyliczającego :

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 użytkowania przykłady z Hash::eachzi bez recursiveflagi:

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

Zobacz także moją rekurencyjną wersję Hash::merge( Hash::merge!) tutaj .

MOPO3OB
źródło