我有几个瓦尔如年,月,日,小时,分钟。我需要对这些值进行一些嵌套散列操作,如hash[2012][12][12][4][3]
。当遇到新的日期时,我需要扩展哈希。是有一个方便的方式来构建嵌套散列红宝石
我可以通过逐个判断每个级别来做到这一点,并创建一个哈希如果不存在。但我想知道有一个方便的方法来做到这一点。
在perl中,我可以调用$hash{$v1}{$v2}{$v3}..{$vN} = something
,因为默认情况下可以创建未定义的哈希。
我有几个瓦尔如年,月,日,小时,分钟。我需要对这些值进行一些嵌套散列操作,如hash[2012][12][12][4][3]
。当遇到新的日期时,我需要扩展哈希。是有一个方便的方式来构建嵌套散列红宝石
我可以通过逐个判断每个级别来做到这一点,并创建一个哈希如果不存在。但我想知道有一个方便的方法来做到这一点。
在perl中,我可以调用$hash{$v1}{$v2}{$v3}..{$vN} = something
,因为默认情况下可以创建未定义的哈希。
我同意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
避免您提到的问题的常用方法是使用块:'h = Hash.new {[]}'。但是你的回答不一定清楚如何延伸到任意深度。 – sawa
为真。我忘记了这个块选项。我刚刚找到了[关于auto-vivification的这个答案](http://stackoverflow.com/a/10130862/717732),它解释了如何使用该选项递归地生成新的散列。 – quetzalcoatl
非常感谢 – akawhy
你可以添加一个辅助方法,你可能在其他情况下找到有用的:
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
以限制添加到当前类。将它放入要包含的模块中可能会很方便。
除非您需要访问中间散列,否则嵌套散列在这里是一个糟糕的设计。我会去分配一个数组作为一个键,即'hash [[2012,12,12,4,3]] =:foo'。 – sawa
或者使用'Date'对象作为键。 –
@sawa感谢您的建议 – akawhy