Як отримати конкретний вихід ітерації хеша в Ruby?


218

Я хочу отримати конкретний вихід ітерації Ruby Hash.

Це хеш, який я хочу повторити:

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

Це результат, який я хотів би отримати:

1-----

a

b

2-----

c

3-----

d 

e

f

g

4-----

h

Як я можу отримати такий результат у Ruby за допомогою мого Hash?


3
Якщо ви повторюєте хеш і очікуєте, що він буде замовлений, вам, ймовірно, потрібно скористатись іншим типом колекції
Аллен Райс

Чи можу я передати значення хешу як варіант перемикача ??
св

Я передаю хеш як варіант перемикача .. але для першого варіанту я отримую перемикач, для інших значень я його не отримую.
св

1
@Allen: Хеші замовлені в Ruby 1.9. Rails також надає OrdersHash (який він використовує лише економно), якщо ви перебуваєте на Ruby <1.9. Дивіться culann.com/2008/01/rails-goodies-activesupportorderedhash
Джеймс А. Росен

Відповіді:


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

Щодо порядку, то слід додати, що в 1.8 пункти будуть повторені у випадковому порядку (ну, власне, у порядку, визначеному хеш-функцією Fixnum), тоді як в 1.9 він буде повторений у порядку буквального.


1
тут що робити, якщо ключ ніде не використовується? . чи потрібно нам поставити ?замість ключа? наприклад: |?, array|це дійсний синтаксис?
huzefa biyawarwala

1
@huzefabiyawarwala Ні, ?це невірна назва змінної в Ruby. Можна використовувати _, але цього не потрібно .
sepp2k

2
@huzefabiyawarwala Так, можна написати|_, v|
sepp2k

1
що використовувати масив змінних імен замість v або значення?
jrhicks

1
@jrhicks Оскільки у OP є хеш, значення якого є масивами.
Радон Росборо

85

Найбільш основний спосіб ітерації над хешем:

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

Так, це має сенс. Чому у відповіді @ sepp2k на клавіші # {}?
відданий

о, неважливо. Я бачив, що це було для стропової інтерполяції
прихильників,


18

Виклик сортування на хеші перетворює його в вкладені масиви, а потім сортує їх за ключем, тому все, що вам потрібно, це:

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

А якщо частину "----" вам фактично не потрібна, це може бути просто:

puts h.sort

Хеш-ключі - це числа, тому '[k + "----"]' піднімає TypeError (String не можна примусити до Fixnum). Вам потрібно '[k.to_s + "----"]'
glenn jackman

Правда досить. У моїй тестовій версії були листи. Виправлено, використовуючи ще кращий "# {k} ----".
glenn mcdonald

10

Моє одне рядкове рішення:

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

Я думаю, що це досить легко читати.


1

Ви також можете уточнити, Hash::each щоб воно підтримувало рекурсивне перерахування. Ось моя версія Hash::each( Hash::each_pair) із підтримкою блоків та перечислювачів :

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

Ось приклади використання Hash::eachіз recursiveпрапором та без нього :

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

Ось приклад із самого питання:

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

Також дивіться мою рекурсивну версію Hash::merge( Hash::merge!) тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.