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?


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.


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

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

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

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.


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 .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.