Как получить конкретный результат, повторяющий хеш в Ruby?

Я хочу получить конкретный результат, повторяющий 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, как я могу получить такой результат с моим хешем?


person sts    schedule 04.08.2009    source источник
comment
Если вы повторяете хэш и ожидаете, что он будет упорядочен, вам, вероятно, потребуется использовать какой-либо другой тип коллекции   -  person Allen Rice    schedule 04.08.2009
comment
Могу ли я передать хеш-значения в качестве переключателя ??   -  person sts    schedule 04.08.2009
comment
Я передаю хэш как вариант с переключателем ... но для первого варианта я получаю переключатель, для других значений я его не получаю.   -  person sts    schedule 04.08.2009
comment
@Allen: Хеши упорядочены в Ruby 1.9. Rails также предоставляет OrderedHash (который используется редко), если вы используете Ruby ‹1.9. См. culann.com/2008/01/rails-goodies-activesupportorderedhash.   -  person James A. Rosen    schedule 04.08.2009


Ответы (5)


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

Что касается порядка, я должен добавить, что в 1.8 элементы будут повторяться в случайном порядке (ну, на самом деле в порядке, определенном хеш-функцией Fixnum), а в 1.9 он будет повторяться в порядке литерала.

person Community    schedule 04.08.2009
comment
вот что если ключ нигде не используется? . нам нужно поставить ? вместо ключа? пример: |?, array| это допустимый синтаксис? - person huzefa biyawarwala; 16.03.2016
comment
@huzefabiyawarwala Нет, ? не является допустимым именем переменной в Ruby. Вы можете использовать _, но не в этом. - person sepp2k; 16.03.2016
comment
я имел в виду, что если мы используем |k,v| для итерации по хешу, но мы не используем k в нашей логической реализации внутри нашего цикла, поэтому есть ли способ написать так |_, v|? - person huzefa biyawarwala; 16.03.2016
comment
@huzefabiyawarwala Да, вы можете написать |_, v| - person sepp2k; 16.03.2016
comment
что использовать массив имен переменных вместо v или значения? - person jrhicks; 05.03.2017
comment
@jrhicks Потому что OP имеет хэш, значения которого являются массивами. - person Radon Rosborough; 13.05.2017

Самый простой способ перебора хеша выглядит следующим образом:

hash.each do |key, value|
  puts key
  puts value
end
person tomascharad    schedule 26.08.2015
comment
Да, это имеет смысл. Почему в ответе @ sepp2k на ключе стоит # {}? - person committedandroider; 04.11.2018
comment
о, неважно. Я видел, что это было для строковой интерполяции - person committedandroider; 04.11.2018

Вызов sort по хешу преобразует его во вложенные массивы, а затем сортирует их по ключу, поэтому все, что вам нужно, это следующее:

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

И если вам действительно не нужна часть со знаком "----", это может быть просто:

puts h.sort
person Community    schedule 04.08.2009
comment
Хеш-ключи являются числами, поэтому '[k + ----]' вызывает TypeError (String не может быть преобразован в Fixnum). Вам нужно '[k.to_s + ----]' - person glenn jackman; 04.08.2009
comment
Достаточно верно. У меня в тестовой версии были буквы. Исправлено с помощью еще лучшего # {k} ----. - person glenn mcdonald; 05.08.2009

Мое однострочное решение:

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

Я думаю, это довольно легко читать.

person Elie Teyssedou    schedule 23.03.2018

Вы также можете уточнить Hash::each, чтобы он поддерживал рекурсивное перечисление. Вот моя версия _2 _ (_ 3_) с поддержкой блока и перечислителя:

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

Также взгляните на мою рекурсивную версию _9 _ (_ 10_) здесь.

person MOPO3OB    schedule 08.03.2018