Comment obtenir une sortie spécifique en itérant un hachage dans Ruby?

218

Je veux obtenir une sortie spécifique en itérant un hachage Ruby.

Voici le Hash sur lequel je veux répéter:

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

Voici la sortie que j'aimerais obtenir:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

Dans Ruby, comment puis-je obtenir une telle sortie avec mon Hash?

m
la source
3
Si vous itérez un hachage et que vous vous attendez à ce qu'il soit commandé, vous devez probablement utiliser un autre type de collection
Allen Rice
puis-je transmettre les valeurs de hachage comme option de bouton radio ??
m
je passe le hachage comme option de bouton radio .. mais pour la première option je reçois un bouton radio, pour d'autres valeurs je ne l'obtiens pas.
m
1
@Allen: Les hachages sont commandés dans Ruby 1.9. Rails fournit également un OrderedHash (qu'il n'utilise qu'avec parcimonie) si vous êtes sur Ruby <1.9. Voir culann.com/2008/01/rails-goodies-activesupportorderedhash
James A. Rosen

Réponses:

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

En ce qui concerne l'ordre, je dois ajouter qu'en 1.8, les éléments seront itérés dans un ordre aléatoire (enfin, en fait dans un ordre défini par la fonction de hachage de Fixnum), tandis qu'en 1.9, il sera itéré dans l'ordre du littéral.

sepp2k
la source
1
ici que faire si la clé n'est utilisée nulle part? . faut-il mettre une ?clé à la place? ex: |?, array|cette syntaxe est-elle valide?
huzefa biyawarwala
1
@huzefabiyawarwala Non, ?n'est pas un nom de variable valide dans Ruby. Vous pouvez l'utiliser _, mais vous n'en avez pas besoin .
sepp2k
2
@huzefabiyawarwala Oui, vous pouvez écrire|_, v|
sepp2k
1
à quoi sert le tableau de noms de variables au lieu de v ou de valeur?
jrhicks
1
@jrhicks Parce que l'OP a un hachage dont les valeurs sont des tableaux.
Radon Rosborough
85

La façon la plus élémentaire d'itérer sur un hachage est la suivante:

hash.each do |key, value|
  puts key
  puts value
end
tomascharad
la source
Oui, cela a du sens. Pourquoi la réponse de @ sepp2k a-t-elle un # {} sur la clé?
committedandroider
Oh peu importe. Je voyais qu'il était pour l' interpolation de chaîne
committedandroider
48
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end
erik
la source
18

L'appel de tri sur un hachage le convertit en tableaux imbriqués, puis les trie par clé, donc tout ce dont vous avez besoin est le suivant:

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

Et si vous n'avez pas réellement besoin de la partie "----", cela peut être juste:

puts h.sort
glenn mcdonald
la source
Les clés de hachage sont des nombres, donc '[k + "----"]' déclenche une TypeError (la chaîne ne peut pas être forcée dans Fixnum). Vous avez besoin de '[k.to_s + "----"]'
glenn jackman
Assez vrai. J'avais des lettres dans ma version d'essai. Correction, en utilisant le meilleur "# {k} ----".
glenn mcdonald
10

Ma solution monoligne:

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

Je pense que c'est assez facile à lire.

Elie Teyssedou
la source
1

Vous pouvez également affiner Hash::each afin qu'il prenne en charge l' énumération récursive . Voici ma version de Hash::each( Hash::each_pair) avec prise en charge des blocs et des énumérateurs :

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

Voici utilisation des exemples de Hash::eachavec et sans recursivedrapeau:

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

Voici un exemple de la question elle-même:

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

Jetez également un œil à ma version récursive de Hash::merge( Hash::merge!) ici .

MOPO3OB
la source