我以为我理解了默认方法对哈希的作用......
如果密钥不存在,则为其提供默认值:
irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = 4
=> 4
irb(main):003:0> a[8]
=> 4
irb(main):004:0> a[9] += 1
=> 5
irb(main):005:0> a
=> {9=>5}
一切都很好。
但如果我将默认值设置为空列表或空哈希,我不明白它在所有的行为....
irb(main):001:0> a = {}
=> {}
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9] # great!
irb(main):004:0> a
=> {} # ?! would have expected {8=>[9]}
irb(main):005:0> a[8]
=> [9] # awesome!
irb(main):006:0> a[9]
=> [9] # unawesome! shouldn't this be [] ??
我希望/期望的行为与我使用|| =运算符...
相同irb(main):001:0> a = {}
=> {}
irb(main):002:0> a[8] ||= []
=> []
irb(main):003:0> a[8] << 9
=> [9]
irb(main):004:0> a
=> {8=>[9]}
irb(main):005:0> a[9]
=> nil
有人可以解释发生了什么吗?
答案 0 :(得分:52)
这是一个非常有用的习语:
(myhash[key] ||= []) << value
它甚至可以嵌套:
((myhash[key1] ||= {})[key2] ||= []) << value
另一种方法是:
myhash = Hash.new {|hash,key| hash[key] = []}
但这有一个重要的副作用,询问关于一个键会创建它,这会渲染has_key吗?相当没用,所以我避免使用这种方法。
答案 1 :(得分:49)
Hash.default
用于设置默认值返回。不会为您创建集合中的条目,只是因为查询它。
此外,您设置default
的值是对象的实例(在您的情况下为数组),因此当返回时,可以对其进行操作。
a = {}
a.default = [] # set default to a new empty Array
a[8] << 9 # a[8] doesn't exist, so the Array instance is returned, and 9 appended to it
a.default # => [9]
a[9] # a[9] doesn't exist, so default is returned
答案 2 :(得分:33)
我认为这是您正在寻找的行为。这将自动将哈希中的任何新键初始化为数组:
irb(main):001:0> h = Hash.new{|h, k| h[k] = []}
=> {}
irb(main):002:0> h[1] << "ABC"
=> ["ABC"]
irb(main):003:0> h[3]
=> []
irb(main):004:0> h
=> {1=>["ABC"], 3=>[]}
答案 3 :(得分:9)
“另一种方法是:
myhash = Hash.new {| hash,key | hash [key] = []}
但这有一个重要的副作用,即询问一个键是否会创建它,这会产生has_key?相当没用,所以我避免使用这种方法。“
事实上似乎并非如此。irb(main):004:0> a = Hash.new {|hash,key| hash[key] = []}
=> {}
irb(main):005:0> a.has_key?(:key)
=> false
irb(main):006:0> a[:key]
=> []
irb(main):007:0> a.has_key?(:key)
=> true
访问密钥将创建它,正如我所料。仅仅问has_key?才不是。
答案 4 :(得分:9)
如果你真的想要一个无休止的深沉哈希:
endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"
当然,正如格伦指出的那样,如果你这样做,那么has_key?失去意义,因为它总会回归真实。对于这一个来说,这是一个jbarnette。
答案 5 :(得分:6)
irb(main):002:0> a.default = []
=> []
irb(main):003:0> a[8] << 9
=> [9] # great!
使用此语句,您已修改默认值;你还没有创建一个新的数组并添加了“9”。在这一点上,如果你这样做了,那就完全相同了:
irb(main):002:0> a.default = [9]
=> [9]
因此,你现在得到这个就不足为奇了:
irb(main):006:0> a[9]
=> [9] # unawesome! shouldn't this be [] ??
此外,'&lt;&lt;&lt;将“9”添加到数组中;它没有将它添加到哈希中,这解释了这一点:
irb(main):004:0> a
=> {} # ?! would have expected {8=>[9]}
而不是使用.default,您可能希望在程序中执行的操作是这样的:
# Time to add a new entry to the hash table; this might be
# the first entry for this key..
myhash[key] ||= []
myhash[key] << value
答案 6 :(得分:-4)
我不确定这是否是你想要的,但你可以这样做,以便在查询丢失的哈希键时总是返回一个空数组。
h = Hash.new { [] }
h[:missing]
=> []
#But, you should never modify the empty array because it isn't stored anywhere
#A new, empty array is returned every time
h[:missing] << 'entry'
h[:missing]
=> []