我以为我理解默认方法对哈希的作用...
如果密钥不存在,请为其提供默认值:
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
谁能解释一下发生了什么?
这是一个非常有用的习语:
(myhash[key] ||= []) << value
它甚至可以嵌套:
((myhash[key1] ||= {})[key2] ||= []) << value
另一种方法是:
myhash = Hash.new {|hash,key| hash[key] = []}
但这有一个重要的副作用,询问一个键是否会创建它,这会产生has_key?相当没用,所以我避免这种方法.
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):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 {| 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?才不是.
如果你真的想要一个无休止的深度哈希:
endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } endless["deep"]["in"]["here"] = "hello"
当然,正如格伦指出的那样,如果你这样做,那么has_key?失去意义,因为它总会回归真实.对于这一个来说,这是一个jbarnette.
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