web-dev-qa-db-fra.com

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

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

Voici le hachage sur lequel je veux parcourir:

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

Voici le résultat que j'aimerais obtenir:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

En Ruby, comment puis-je obtenir une telle sortie avec mon hachage?

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

En ce qui concerne l’ordre, j’ajouterai que dans la version 1.8, les éléments seront itérés dans un ordre aléatoire (en fait, dans un ordre défini par la fonction de hachage de Fixnum), alors que dans la version 1.9, ils seront itérés dans l’ordre du littéral.

312
sepp2k

Le moyen le plus simple d'itérer sur un hachage est le suivant:

hash.each do |key, value|
  puts key
  puts value
end
81
tomascharad
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end
48
erik

L'appel d'un tri sur un hachage le convertit en tableaux imbriqués, puis les trie par clé. Vous n'avez donc besoin que de ceci:

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

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

puts h.sort
17
glenn mcdonald

Ma solution en une seule ligne:

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

Je pense que c'est assez facile à lire.

9
Elie Teyssedou

Vous pouvez également raffiner Hash::each afin qu'il prenne en charge récursif énumération. Voici ma version de Hash::each (Hash::each_pair) avec bloc et énumérateur support:

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 des exemples d'utilisation de Hash::each avec et sans recursive flag:

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 tiré 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 coup d'œil à ma version récursive de Hash::merge (Hash::merge!) ici .

1
MOPO3OB