我以为我理解默认方法对哈希的作用......

如果键不存在,则为其指定默认值:

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 用于设置默认值 当你查询一个不存在的key时。集合中的条目不是为您创建的,只是因为查询了它。

另外,您设置的值 default to 是一个对象的实例(在你的例子中是一个数组),所以当它返回时,它可以被操作。

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] = []}

但这有一个显着的副作用: 询问 about a key 将创建它,这会呈现 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 {|哈希,键|哈希[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"

当然,正如 Glenn 上面指出的,如果你这样做,has_key?失去了它的意义,因为它总是返回 true。感谢 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

我不确定这是否是您想要的,但是您可以这样做,以便在查询丢失的哈希键时始终返回空数组。

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]
   => []
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top