将ruby hash .default设置为列表

时间:2008-10-10 10:28:53

标签: ruby hashmap

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

如果密钥不存在,则为其提供默认值:

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

有人可以解释发生了什么吗?

7 个答案:

答案 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]
   => []