设置ruby哈希默认为列表
我以为我明白了什么是默认的方法做一个哈希…
如果键不存在,请为其提供默认值:
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
用于设置查询不存在的键时返回的默认值。 集合中的条目不是为您创build的,只是因为查询它。
另外,你设置的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
这是一个非常有用的习惯用法:
(myhash[key] ||= []) << value
它甚至可以嵌套:
((myhash[key1] ||= {})[key2] ||= []) << value
另一种方法是做:
myhash = Hash.new {|hash,key| hash[key] = []}
但是这有一个重要的副作用,那就是询问一个关键字是否会创build一个has_key? 相当无用,所以我避免了这种方法。
我认为这是你正在寻找的行为。 这将自动初始化哈希中的任何新密钥到一个数组:
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] = []}
但是这有一个重要的副作用,就是询问关键字是否会创buildhas_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
如我所料, 访问密钥将创build它。 仅仅问has_key? 才不是。
如果你真的想有一个无穷无尽的哈希:
endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } endless["deep"]["in"]["here"] = "hello"
当然,正如Glenn指出的那样,如果你这样做,has_key? 失去它的意义,因为它将永远回报真实。 Thx为这个jbarnette。
irb(main):002:0> a.default = [] => [] irb(main):003:0> a[8] << 9 => [9] # great!
有了这个声明,你已经修改了默认值; 你还没有创build一个新的数组,并添加“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
我不知道这是否是你想要的,但是你可以这样做,当查询丢失的散列键时总是返回一个空数组。
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] => []