红宝石哈希.DEFAULT设置为一个列表
我想我明白了默认的方法做一个哈希...红宝石哈希.DEFAULT设置为一个列表
给一个键的默认值,如果不存在的话:
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
任何人都可以解释发生了什么事吗?
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
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 [] ??
此外,“< <”添加“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
这是一个非常有用的成语:
(myhash[key] ||= []) << value
它甚至可以被嵌套:
((myhash[key1] ||= {})[key2] ||= []) << value
另一种方式是做:
myhash = Hash.new {|hash,key| hash[key] = []}
但这有显著副作用,即询问约一键将创建它,这使得对象的has_key?相当无用,所以我避免了这种方法。
我不确定这是否是你想要的,但是你可以这样做,当查询丢失的散列键时总是返回一个空数组。
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]
=> []
我认为这是您正在寻找的行为。这将自动初始化哈希任何新键的数组:
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=>[]}
格伦·麦克唐纳说:
“的另一种方法是做:
myhash = Hash.new {|哈希, 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?才不是。
如果你真的想有一个深不休哈希:
endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"
当然,正如上面格伦指出,如果你做到这一点,对象的has_key?它的意义会失去它的意义,因为它总会回归真实。 Thx to jbarnette为这一个。
很好的解释,有道理 – 2008-10-10 11:01:09
我想指出,这种行为是不同于python的defaultdict,其中类似的代码工作得很好。 – 2012-10-10 07:57:03