在Ruby中将键/值对附加到<<


80

在Ruby中,可以使用<<将值附加到现有数组中:

a = []
a << "foo"

但是,您还可以将键/值对附加到现有的哈希吗?

h = {}
h << :key "bar"

我知道你可以做:

h[:key] = ""
h[:key] << "bar"

但这不是我想要的。

谢谢。


20
为什么不h[:key] = "bar"呢?
Hauleth 2013年

4
这不起作用:h[:key] << "bar"
克里斯·尼尔森

Answers:


141

merge!

h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}

3
我不认为merge!仅仅创建一个新的键/值对就符合资格,因为它实际上已用于其他目的。
PericlesTheo

好点子。我认为,最终结果可能还取决于OP未发布的其他因素。
迈克尔·杜兰特

1
嗯谢谢 看起来store方法做了类似的事情。这主要是一个学术问题,正如我所见<< <<是一种附加到数组的方法,但想查看它是否适用于哈希。再次感谢。
jcarpio

5
区别在于:store只需添加一对新密钥,就不必关心密钥是否已存在。与merge!然而,有重复键条目被覆盖所以这种方法并不仅仅是增加对位。如果对这两者进行基准测试,则会发现store速度更快(但琐碎,但尤其是在较小的哈希值上)
PericlesTheo

2
@jcarpio谢谢。Hash#merge!返回接收方哈希值,就像Array#<<返回接收方数组一样。Hash#store是完全不同的事情。另外,key: "bar"在参数位置使用哈希语法糖时,我认为这是最接近您的符号的方法。我知道这更接近您想要的。
sawa

89

由于哈希不是固有地排序的,因此没有附加的概念。从1.9开始,Ruby哈希保持插入顺序。这是添加新的键/值对的方法。

最简单的解决方案是

h[:key] = "bar"

如果需要一种方法,请使用store

h.store(:key, "bar")

如果确实要使用“铲子”运算符(<<),则它实际上是作为数组附加到哈希值中,并且必须指定键:

h[:key] << "bar"

以上仅在密钥存在时起作用。要附加新密钥,您必须使用默认值初始化哈希,您可以像这样进行操作:

h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"

您可能会想办法对Hash进行修补,以包括一个以您编写方式工作的铲子运算符:

class Hash
  def <<(k,v)
    self.store(k,v)
  end
end

但是,这不会继承在其他情况下应用于铲子运算符的“语法糖”:

h << :key, "bar" #doesn't work
h.<< :key, "bar" #works

彻底!感谢您的贡献和见识。
jcarpio

需要注意的是,从Ruby 1.9开始,哈希值是有序的。

1
Ruby 1.9+保持插入顺序,但是Hash作为数据结构没有任何固有顺序的概念。
马克·托马斯

26

不,我认为您不能附加键/值对。我知道的唯一最接近的东西是使用store方法:

h = {}
h.store("key", "value")

3

也许您想要Hash#merge?

1.9.3p194 :015 > h={}
 => {} 
1.9.3p194 :016 > h.merge(:key => 'bar')
 => {:key=>"bar"} 
1.9.3p194 :017 > 

如果您想就地更改数组,请使用 merge!

1.9.3p194 :016 > h.merge!(:key => 'bar')
 => {:key=>"bar"} 

我不认为merge这是个好主意,因为它返回一个新数组。不将新对添加到现有哈希中。
PericlesTheo

怎么样merge!(即到现有数组)而不是merge
迈克尔·杜兰特

1
merge!从技术上讲,在这种情况下有效,但我认为应该将其用于合并两个哈希,而不是简单地添加一对新哈希。另外,如果您进行基准测试merge!,它会比store;;慢
PericlesTheo

3

与它们类似,merge!并且根据键名store现有哈希进行不同的处理,因此将影响您的偏好。从语法的角度来看,merge!key: "value"语法与JavaScript和Python紧密匹配。我一直以来都讨厌以逗号分隔键/值对。

hash = {}
hash.merge!(key: "value")
hash.merge!(:key => "value")
puts hash

{:key=>"value"}

hash = {}
hash.store(:key, "value")
hash.store("key", "value")
puts hash

{:key=>"value", "key"=>"value"}

为了使铲斗操作员<<工作,我建议使用马克·托马斯的答案。


1

我必须做类似的事情,但是我需要使用相同的键添加值。使用合并或更新时,无法使用相同的键推送值。所以我不得不使用哈希数组。

    my_hash_static = {:header =>{:company => 'xx', :usercode => 'xx', :password => 'xx',
                      :type=> 'n:n', :msgheader => from}, :body=>[]}
    my_hash_dynamic = {:mp=>{:msg=>message, :no=>phones} }        
    my_hash_full = my_hash_static[:body].push my_hash_dynamic
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.