当前位置:  开发笔记 > 后端 > 正文

将ruby hash .default设置为列表

如何解决《将rubyhash.default设置为列表》经验,为你挑选了6个好方法。

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

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

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

谁能解释一下发生了什么?



1> glenn mcdona..:

这是一个非常有用的习语:

(myhash[key] ||= []) << value

它甚至可以嵌套:

((myhash[key1] ||= {})[key2] ||= []) << value

另一种方法是:

myhash = Hash.new {|hash,key| hash[key] = []}

但这有一个重要的副作用,询问一个键是否会创建它,这会产生has_key?相当没用,所以我避免这种方法.


我不认为最后一种技术的副作用存在于ruby 1.9.2中.myhash = Hash.new {| hash,key | hash [key] = []}; myhash.has_key?(:test)#=> false
哦,不,我的意思是"把myhash [:test]"等等,看起来它应该是无害的,现在会导致`myhash.has_key?(:test)`之后是真的.

2> Aaron Hinni..:

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


哇,这很可怕,并且通过动态更改此默认值非常容易出错.我只花了3个小时试图弄清楚在尝试将默认值设置为[]时wtf正在进行中.IMNSHO,默认不应该这样暴露.替代方案(h = Hash.new {| h,k | h [k] = []})并没有真正做到我想要的,因为它总是通过引用哈希键来创建一个新数组.现在我回到做我想避免的事情:h [k] = []除非h.has_key?(k):)
我希望你们不仅仅因为Ruby本身的特殊性而对这个答案进行了投票:)这个解释性的答案出了什么问题?直到我看到强调"返回"并解释"默认"作为对象的价值的重要性时,我自己并没有完全理解这个概念(因此它在随后的不存在的键调用中保持不变).

3> Turp..:

我认为这是你正在寻找的行为.这将自动将哈希中的任何新键初始化为数组:

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



4> jrochkind..:

格伦麦克唐纳说:

"另一种方法是:

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?才不是.



5> 小智..:

如果你真的想要一个无休止的深度哈希:

endless = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
endless["deep"]["in"]["here"] = "hello"

当然,正如格伦指出的那样,如果你这样做,那么has_key?失去意义,因为它总会回归真实.对于这一个来说,这是一个jbarnette.



6> Simon Howard..:
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

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有