Append key/value pair to hash with << in Ruby
Solution 1
There is merge!
.
h = {}
h.merge!(key: "bar")
# => {:key=>"bar"}
Solution 2
Since hashes aren't inherently ordered, there isn't a notion of appending. Ruby hashes since 1.9 maintain insertion order, however. Here are the ways to add new key/value pairs.
The simplest solution is
h[:key] = "bar"
If you want a method, use store
:
h.store(:key, "bar")
If you really, really want to use a "shovel" operator (<<
), it is actually appending to the value of the hash as an array, and you must specify the key:
h[:key] << "bar"
The above only works when the key exists. To append a new key, you have to initialize the hash with a default value, which you can do like this:
h = Hash.new {|h, k| h[k] = ''}
h[:key] << "bar"
You may be tempted to monkey patch Hash to include a shovel operator that works in the way you've written:
class Hash
def <<(k,v)
self.store(k,v)
end
end
However, this doesn't inherit the "syntactic sugar" applied to the shovel operator in other contexts:
h << :key, "bar" #doesn't work
h.<< :key, "bar" #works
Solution 3
No, I don't think you can append key/value pairs. The only thing closest that I am aware of is using the store
method:
h = {}
h.store("key", "value")
Solution 4
Similar as they are, merge!
and store
treat existing hashes differently depending on keynames, and will therefore affect your preference. Other than that from a syntax standpoint, merge!
's key: "value"
syntax closely matches up against JavaScript and Python. I've always hated comma-separating key-value pairs, personally.
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"}
To get the shovel operator <<
working, I would advise using Mark Thomas's answer.
Solution 5
Perhaps you want Hash#merge ?
1.9.3p194 :015 > h={}
=> {}
1.9.3p194 :016 > h.merge(:key => 'bar')
=> {:key=>"bar"}
1.9.3p194 :017 >
If you want to change the array in place use merge!
1.9.3p194 :016 > h.merge!(:key => 'bar')
=> {:key=>"bar"}
jcarpio
Updated on July 08, 2022Comments
-
jcarpio almost 2 years
In Ruby, one can append values to existing arrays using <<:
a = [] a << "foo"
but, can you also append key/value pairs to an existing hash?
h = {} h << :key "bar"
I know you can do:
h[:key] = "" h[:key] << "bar"
but that's not I want.
Thanks.
-
PericlesTheo over 10 yearsI don't think
merge!
qualifies as simply creating a new key/value pair as it's actually used for another purpose. -
Michael Durrant over 10 yearsGood point. I think it may also end up depending on other factors that the OP didn't post.
-
PericlesTheo over 10 yearsI don't think
merge
it's a good idea because it returns a new array; not adding the new pair to the existing hash. -
Michael Durrant over 10 yearsHow about the
merge!
(i.e. to existing array) instead ofmerge
? -
PericlesTheo over 10 years
merge!
technically works in this context but I think it should be used for merging two hashes rather than simply adding a new pair. Also, if you benchmarkmerge!
, it's slower thanstore
;) -
jcarpio over 10 yearsAh, thanks. Looks like the store method does something similar. This was mostly an academic question as I've seen << referred as a way to append to arrays but wanted to see if it worked for hashes. Thanks again.
-
PericlesTheo over 10 yearsThe difference is this:
store
simply adds a new pair, it doesn't care if the key already exists. withmerge!
however, entries with duplicate keys are overridden so the method does a bit more than just adding pairs. If you benchmark the two, you will findstore
to be faster(trivial however especially on small hashes) -
sawa over 10 years@jcarpio Thanks.
Hash#merge!
returns the receiver hash just likeArray#<<
returns the receiver array.Hash#store
is a completely different thing. Also, with the hash syntax sugarkey: "bar"
in the argument position, I thought this was the closest you can get to your notation. I knew this one is closer to what you wanted. -
jcarpio over 10 yearsThorough! Thanks for the contribution and insight.
-
Will almost 10 yearsThank you so much! I was having a problem adding multiple values. I was trying hash[:a] = 1 hash[:b] = 2 puts hash[:a] output 1,2 The merge! fixed this issue, now hash[:a] output 1
-
steel about 9 yearsTo note, as of Ruby 1.9, Hashes are ordered.
-
Mark Thomas about 9 yearsRuby 1.9+ maintains insertion order, but a Hash as a data structure doesn't have the concept of any kind of inherent order.