Ruby中的一个内嵌嵌套哈希创建? (我来自Perl)

时间:2010-07-26 21:01:30

标签: ruby perl hash nested

我是一名Perl人,我已经将Hashes这样做了一段时间:

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                                                                                                                                                           
              }                                                                                                                                                                    
            }                                                                                                                                                                      
          }                                                                                                                                                                        
        }                                                                                                                                                                                                                                                                                                                                                     
      }                   

9 个答案:

答案 0 :(得分:44)

不幸的是,没有简单,实用的方式。一个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

答案 1 :(得分:17)

这里有几个类似于@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

答案 2 :(得分:17)

->f{f[f]}[->f{Hash.new{|h,k|h[k]=f[f]}}]

显然。

答案 3 :(得分:13)

与上面给出的lambda表达式相比,这更简单,也在一行中:

Hash.new {|h,k| h[k] = Hash.new(&h.default_proc) }

答案 4 :(得分:2)

使用符号似乎有效:

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}}}

答案 5 :(得分:1)

看起来Ruby从一开始就不能进行自动修复,但您可以轻松添加该功能。在Google上搜索“ruby autovivification”会给出:

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

其中包含一个很好的示例,说明如何创建一个可以按照您要查找的方式工作的哈希。

ruby hash autovivification (facets)也可能会有所帮助。

答案 6 :(得分:1)

你可以使用Facets gem Hash.autonew来做与Molf答案中给出的recursive函数相同的事情。

答案 7 :(得分:0)

require 'xkeys'
date = {}.extend XKeys::Hash

date[month, day, hours, min, sec, :else => 0] += 1

答案 8 :(得分:0)

1) 改进

您可以使用 Ruby Refinements 而不是 Monkey Patching

比 MonkeyPatching 整个 Hash 类更安全,使用部分还是很花哨的

设置?‍?

# Use Hash.dynamic_keys to create keys dynamically on a Hash
module HashDynamicKeysRefinements
  refine Hash.singleton_class do
    def dynamic_keys
      new { |hash, key| hash[key] = dynamic_keys }
    end
  end
end

用法?

using HashDynamicKeysRefinements

dynamic_hash = Hash.dynamic_keys

dynamic_hash[:where][:requests][:id] = 3

dynamic_hash
=> {:where=>{:requests=>{:id=>3}}}

2) 新班级

或者你可以在Hash类上新建一个类来实现这个功能,使用部分也很赞。

设置?‍?

  • /lib/hash_dynamic.rb
# Enables dynamic keys creation on a Hash
#   query = Hash.dynamic_keys
#   query[:where][:requests][:id] = 3
#   puts query
#     {:where=>{:requests=>{:id=>3}}}
class HashDynamic < Hash
  def self.new
    Hash.new { |hash, key| hash[key] = new }
  end
end

用法?

require 'hash_dynamic.rb'

dynamic_hash = HashDynamic.new

dynamic_hash[:a][:b][:c] = 5

dynamic_hash
=> {:a=>{:b=>{:c=>5}}}