Ruby Hash交互与推入阵列

时间:2014-04-02 14:40:37

标签: ruby hash

所以,让我们说我做了以下事情:

lph = Hash.new([])       #=> {}
lph["passed"] << "LCEOT" #=> ["LCEOT"]
lph                      #=> {} <-- Expected that to have been {"passed" => ["LCEOT"]}
lph["passed"]            #=> ["LCEOT"]
lph["passed"] = lph["passed"] << "HJKL"
lph #=> {"passed"=>["LCEOT", "HJKL"]}

我对此感到惊讶。几个问题:

  1. 为什么在我将第二个字符串推送到数组之前它不会被设置?背景中发生了什么?
  2. 从本质上说,更为惯用的红宝石方式是什么?我有一个哈希,一个键和一个值,我希望最终在与键相关联的数组中。如何在第一次将与键关联的数组中的值推送到哈希中。在以后的所有密钥使用中,我只想添加到数组中。

2 个答案:

答案 0 :(得分:6)

仔细阅读Ruby Hash.new documentation - &#34;如果随后通过与散列条目不对应的密钥访问此散列,则返回的值取决于用于创建散列的新样式&# 34。

  

new(obj)→new_hash

     

...如果指定了obj,此单个对象将用于所有默认值

在您的示例中,您尝试将某些内容推送到与不存在的键相关联的值上,因此您最终会改变最初用于构造哈希的相同匿名数组。

the_array = []
h = Hash.new(the_array)
h['foo'] << 1 # => [1]
# Since the key 'foo' was not found
# ... the default value (the_array) is returned
# ... and 1 is pushed onto it (hence [1]).
the_array # => [1]
h # {} since the key 'foo' still has no value.

您可能想要使用块形式:

  

new {| hash,key | block}→new_hash

     

...如果指定了一个块,它将使用哈希对象和键调用,并应返回默认值。如果需要,该块负责将值存储在哈希值中。

例如:

h = Hash.new { |hash, key| hash[key] = [] } # Assign a new array as default for missing keys.
h['foo'] << 1 # => [1]
h['foo'] << 2 # => [1, 2]
h['bar'] << 3 # => [3]
h # => { 'foo' => [1, 2], 'bar' => [3] }

答案 1 :(得分:3)

为什么在我将第二个字符串推送到数组之前它不会被设置?

总之;因为你没有在散列中设置任何东西,直到这一点,你也将第二个字符串添加到数组。

后台发生了什么?

要了解后台发生了什么,让我们一次采取这一行:

lph = Hash.new([])       #=> {}

这会创建一个空哈希,配置为每当访问不存在的密钥时返回[]对象。

lph["passed"] << "LCEOT" #=> ["LCEOT"]

这可以写成

value = lph["passed"] #=> []
value << "LCEOT"      #=> ["LCEOT"]

我们看到lph["passed"]按预期返回[],然后我们继续将"LCEOT"追加到[]

lph                  #=> {}

lph仍为空Hash。我们在任何时候都没有向Hash添加任何内容。我们已将某些内容添加到其默认值,但这不会更改lph本身。

lph["passed"]        #=> ["LCEOT"]

这是有趣的地方。当我们value << ["LCEOT"]时,请记住上面的内容。这实际上改变了lph在找不到密钥时返回的默认值。默认值不再是[],而是已成为["LCEOT"]。这里返回了新的默认值。

lph["passed"] = lph["passed"] << "HJKL"

这是我们对lph的第一次更改。我们实际分配给lph["passed"]的是默认值(因为"passed"仍然是lph中不存在的密钥)并且附加了"HJKL"。在此之前,默认值为["LCEOT"],此后为["LCEOT", "HJKL"]

换句话说,lph["passed"] << "HJKL"会返回["LCEOT", "HJKL"],然后会将其分配给lph["passed"]

什么是惯用的Ruby方式

使用<<=

>> lph = Hash.new { [] }
=> {}
>> lph["passed"] <<= "LCEOT"
=> ["LCEOT"]
>> lph
=> {"passed"=>["LCEOT"]}

还要注意使用块而不是逐字数组初始化哈希的方式的变化。这样可以确保在访问新密钥时创建并返回一个新的空白数组,而不是每次都使用相同的数组。