Один лайнер вложенный хэш создания в Ruby?(Я из Perl) - PullRequest
26 голосов
/ 27 июля 2010

Я человек Perl, и я какое-то время делал такие Хеши:

my %date;

#Assume the scalars are called with 'my' earlier

$date{$month}{$day}{$hours}{$min}{$sec}++

Теперь я изучаю Ruby и до сих пор обнаружил, что использование этого дерева - это способ получить много ключей и значение. Есть ли способ использовать простой формат, который я использую с Perl, используя одну строку?

 @date = {                                                                                                                                                                      
        month => {                                                                                                                                                                 
          day => {                                                                                                                                                                 
           hours => {                                                                                                                                                              
              min => {                                                                                                                                                             
                sec => 1                                                                                                                                                           
              }                                                                                                                                                                    
            }                                                                                                                                                                      
          }                                                                                                                                                                        
        }                                                                                                                                                                                                                                                                                                                                                     
      }                   

Ответы [ 7 ]

45 голосов
/ 27 июля 2010

К сожалению, не существует простого, практичного способа .Эквивалент Ruby будет выглядеть как уродливый, уродливый зверь:

((((@date[month] ||= {})[day] ||= {})[hours] ||= {})[min] ||= {})[sec] = 1

Существует способ назначить значения по умолчанию для отсутствующих ключей в хешах, однако:

@date = Hash.new { |hash, key| hash[key] = {} }

# @date[:month] is set to a new, empty hash because the key is missing.
@date[:month][:day] = 1

К сожалению, это не работает рекурсивно.

... если только вы не создадите его сами ;Ура для Ruby!

class Hash
  def self.recursive
    new { |hash, key| hash[key] = recursive }
  end
end

@date = Hash.recursive
@date[month][day][hours][min][sec] = 1
# @date now equals {month=>{day=>{hours=>{min=>{sec=>1}}}}}

Имейте в виду, что все неустановленные значения теперь {}, а не nil.

17 голосов
/ 11 июля 2013
->f{f[f]}[->f{Hash.new{|h,k|h[k]=f[f]}}]

Очевидно.

17 голосов
/ 01 мая 2013

Вот пара вариантов, похожих на ответ, данный @molf, но без патча обезьяны.

Использование фабричного метода:

  def hash_tree
    Hash.new do |hash, key|
      hash[key] = hash_tree
    end
  end

  @date = hash_tree
  @date[month][day][hours][min][sec] = 1

С пользовательским классом:

  class HashTree < Hash
    def initialize
      super do |hash, key|
        hash[key] = HashTree.new
      end
    end
  end

  @date = HashTree.new
  @date[month][day][hours][min][sec] = 1
13 голосов
/ 18 августа 2014

По сравнению с лямбда-выражением, приведенным выше, это проще и также в одной строке:

Hash.new {|h,k| h[k] = Hash.new(&h.default_proc) }
2 голосов
/ 27 июля 2010

Использование символов, похоже, работает:

ree-1.8.7-2009.10 > @date = {:month =>{:day => {:hours => {:min => {:sec => 1 } } } } }
 => {:month=>{:day=>{:hours=>{:min=>{:sec=>1}}}}} 

Затем я могу получить значение val следующим образом:

ree-1.8.7-2009.10 > @date[:month][:day]
 => {:hours=>{:min=>{:sec=>1}}}
1 голос
/ 27 июля 2010

Вы можете использовать Facets gem's Hash.autonew, чтобы сделать то же самое, что и функция recursive, приведенная в ответе Мольфа.

1 голос
/ 27 июля 2010

Не похоже, что Ruby может выполнять автовификацию с самого начала, но вы можете легко добавить эту функциональность. Поиск по "ruby autovivification" в Google дает:

http://t -a-w.blogspot.com / 2006/07 / autovivification-в-ruby.html

Который содержит хороший пример того, как создать хеш, который будет работать так, как вы ищете.

Автовификация рубинового хэша (фасеты) также может быть полезным.

...