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.