2013-12-14 20 views
0

我有几个瓦尔如日,小时分钟。我需要对这些值进行一些嵌套散列操作,如hash[2012][12][12][4][3]。当遇到新的日期时,我需要扩展哈希。是有一个方便的方式来构建嵌套散列红宝石

我可以通过逐个判断每个级别来做到这一点,并创建一个哈希如果不存在。但我想知道有一个方便的方法来做到这一点。

在perl中,我可以调用$hash{$v1}{$v2}{$v3}..{$vN} = something,因为默认情况下可以创建未定义的哈希。

+2

除非您需要访问中间散列,否则嵌套散列在这里是一个糟糕的设计。我会去分配一个数组作为一个键,即'hash [[2012,12,12,4,3]] =:foo'。 – sawa

+2

或者使用'Date'对象作为键。 –

+1

@sawa感谢您的建议 – akawhy

回答

1

我同意sawa的评论。这种方法可能会遇到很多其他问题。但是,你想要的是可能的。

搜索“ruby hash默认值”。

默认情况下,哈希表项的默认值为nil。当问及对不存在的键将返回5,而不是零

h = Hash.new(5) 

现在h:您可以更改,即。您可以命令它以类似的方式返回一个新的空数组或新的空哈希。

但是,要小心。意外地通过所有条目共享默认实例很容易。

h = Hash.new([]) // default value = Array object, let's name it X 
one = h[:dad] // returns THE SAME object X 
two = h[:mom] // returns THE SAME object X 

您必须小心不要使用shared-default-instance,并使用不会改变它的操作。你不能只是

h[:mom] << 'thing' 

h[:brandnewone]现在将返回突变默认实例与“事”里。

See here for a good explanation and proper usage examples

,或者甚至更好:example of autovivifying hash

+1

避免您提到的问题的常用方法是使用块:'h = Hash.new {[]}'。但是你的回答不一定清楚如何延伸到任意深度。 – sawa

+0

为真。我忘记了这个块选项。我刚刚找到了[关于auto-vivification的这个答案](http://stackoverflow.com/a/10130862/717732),它解释了如何使用该选项递归地生成新的散列。 – quetzalcoatl

+0

非常感谢 – akawhy

1

你可以添加一个辅助方法,你可能在其他情况下找到有用的:

def mfetch(hash, *keys) 
    return nil if (keys.empty? || !hash[keys.first]) 
    return hash[keys.first] if keys.size == 1 
    k = keys.shift 
    raise ArgumentError, "Too many keys" unless hash[k].is_a? Hash 
    return mfetch(hash[k], *keys) 
end 

h = {cat: {dog: {pig: 'oink'}}} # => {:cat=>{:dog=>{:pig=>"oink"}}} 
mfetch(h, :cat, :dog, :pig)  # => "oink" 
mfetch(h, :cat, :dog)    # => {:pig=>"oink"} 
mfetch(h, :cat)     # => {:dog=>{:pig=>"oink"}} 
mfetch(h, :cow)     # => nil 
mfetch(h, :cat, :cow)    # => nil 
mfetch(h, :cat, :dog, :cow)  # => nil 
mfetch(h, :cat, :dog, :pig, :cow) # => ArgumentError: Too many keys 

如果首选,您可以改为添加到Hash类的方法:

class Hash 
    def mfetch(*keys) 
    return nil if (keys.empty? || !hash[keys.first]) 
    return self[keys.first] if keys.size == 1 
    k = keys.shift 
    raise ArgumentError, "Too many keys" unless self[k].is_a? Hash 
    return self[k].mfetch(*keys) 
    end 
end 

h.mfetch(:cat, :dog, :pig)   # => "oink" 

或者如果您使用的是Ruby 2.0,请将class Hash替换为refine Hash do以限制添加到当前类。将它放入要包含的模块中可能会很方便。