Come ottenere un output specifico ripetendo un hash in Ruby?


218

Voglio ottenere un output specifico che riproduca un Ruby Hash.

Questo è l'hash che voglio ripetere:

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

Questo è l'output che vorrei ottenere:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

In Ruby, come posso ottenere un simile output con il mio hash?


3
Se stai ripetendo un hash e ti aspetti che venga ordinato, probabilmente dovrai utilizzare un altro tipo di raccolta
Allen Rice,

posso passare i valori di hash come opzione del pulsante di opzione ??
m

sto passando l'hash come opzione del pulsante di opzione .. ma per la prima opzione sto ricevendo il pulsante di opzione, per altri valori non lo ottengo.
m

1
@Allen: gli hash sono ordinati in Ruby 1.9. Rails fornisce anche un OrderedHash (che usa solo con parsimonia) se sei su Ruby <1.9. Vedi culann.com/2008/01/rails-goodies-activesupportorderedhash
James A. Rosen

Risposte:


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

Per quanto riguarda l'ordine, dovrei aggiungere che in 1.8 gli articoli verranno ripetuti in ordine casuale (beh, in realtà in un ordine definito dalla funzione di hashing di Fixnum), mentre in 1.9 verrà ripetuto nell'ordine letterale.


1
qui cosa succede se la chiave non viene utilizzata da nessuna parte? . dobbiamo mettere un ?posto al posto della chiave? es: |?, array|questa sintassi è valida?
Huzefa Biyawarwala,

1
@huzefabiyawarwala No, ?non è un nome di variabile valido in Ruby. Puoi usare _, ma non è necessario .
sepp2k,

2
@huzefabiyawarwala Sì, puoi scrivere|_, v|
sepp2k,

1
che cosa usa la matrice di nomi di variabili anziché v o value?
jrhicks,

1
@jrhicks Perché l'OP ha un hash i cui valori sono array.
Radon Rosborough,

85

Il modo più semplice per iterare su un hash è il seguente:

hash.each do |key, value|
  puts key
  puts value
end

Sì, questo ha senso. Perché la risposta di @ sepp2k ha un # {} sulla chiave?
committedandroider

Oh non importa. Ho visto che era per interpolazione di stringhe
committedandroider

48
hash.keys.sort.each do |key|
  puts "#{key}-----"
  hash[key].each { |val| puts val }
end

18

Chiamare l'ordinamento su un hash lo converte in array nidificati e poi li ordina per chiave, quindi tutto ciò che serve è questo:

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

E se in realtà non hai bisogno della parte "----", può essere solo:

puts h.sort

Le chiavi hash sono numeri, quindi '[k + "----"]' genera un TypeError (String non può essere forzato in Fixnum). Hai bisogno di '[k.to_s + "----"]'
glenn jackman il

Abbastanza vero. Avevo delle lettere nella mia versione di prova. Risolto, usando anche il migliore "# {k} ----".
Glenn McDonald,

10

La mia soluzione a una linea:

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

Penso che sia abbastanza facile da leggere.


1

Puoi anche perfezionare in Hash::each modo da supportare l' enumerazione ricorsiva . Ecco la mia versione di Hash::each( Hash::each_pair) con supporto per blocco ed enumeratore :

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

Ecco alcuni esempi di utilizzo di Hash::eachcon e senza recursiveflag:

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

Ecco un esempio dalla domanda stessa:

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

Dai anche un'occhiata alla mia versione ricorsiva di Hash::merge( Hash::merge!) qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.