How can I do h["foo"] += "bar" if h["foo"] does not exist?

Hi there,

I have a hash with various keys and values that are strings.

If the key exists, the following works: h[“foo”] += “bar”

But if the key does not exist, I get an error.

Is it possible in one statement to cover both the cases where the key
does exist (as above) AND the case where the key does not exist - and in
this situation I’d like the new key and value pair to be created in the
hash.

Any help gratefully received!

  • A

Andrew S. писал 09.12.2011 09:58:

does exist (as above) AND the case where the key does not exist - and
in
this situation I’d like the new key and value pair to be created in
the
hash.

Any help gratefully received!

  • A

$ irb
ruby-1.9.3-p0 :001 > hash = Hash.new("")
=> {}
ruby-1.9.3-p0 :002 > hash[:a] = “test”
=> “test”
ruby-1.9.3-p0 :003 > hash[:a] += " - one"
=> “test - one”
ruby-1.9.3-p0 :004 > hash[:b] += “nothing - two”
=> “nothing - two”
ruby-1.9.3-p0 :005 > hash
=> {:a=>“test - one”, :b=>“nothing - two”}

On Dec 8, 2011, at 21:58 , Andrew S. wrote:

Hi there,

I have a hash with various keys and values that are strings.

If the key exists, the following works: h[“foo”] += “bar”

That only works if the value at key “foo” responds to +. In this case, I
presume, a String.

But if the key does not exist, I get an error.

You only get an error because nil (the default default value) doesn’t
respond to +.

Is it possible in one statement to cover both the cases where the key
does exist (as above) AND the case where the key does not exist - and in
this situation I’d like the new key and value pair to be created in the
hash.

Assuming you want an empty string as your default value:

h = Hash.new { |h,k| h[k] = "" }

That will initialize your hash ‘h’ with a default value proc that gets
run every time you access a key that isn’t yet a member of h. That proc
is passed the hash (self) and they key. We assign a new empty string at
h[k].

On Fri, Dec 9, 2011 at 12:11 AM, Ryan D.
[email protected]wrote:

But if the key does not exist, I get an error.
$ irb

default object.

Additionally:

hash = Hash.new(“”)

modifying the key doesn’t set the key

hash[:foo] << ‘blah’
hash.keys # => []

it modifies the default

hash.default # => “blah”
hash[:foo] # => “blah”
hash[:bar] # => “blah”

On Fri, Dec 09, 2011 at 02:58:18PM +0900, Andrew S. wrote:

hash.
I guess you could get really ugly with it.

h['foo'] = h['foo'].to_s + 'bar'

On Dec 8, 2011, at 22:03 , Peter Z. wrote:

does exist (as above) AND the case where the key does not exist - and in
ruby-1.9.3-p0 :002 > hash[:a] = “test”
=> “test”
ruby-1.9.3-p0 :003 > hash[:a] += " - one"
=> “test - one”
ruby-1.9.3-p0 :004 > hash[:b] += “nothing - two”
=> “nothing - two”
ruby-1.9.3-p0 :005 > hash
=> {:a=>“test - one”, :b=>“nothing - two”}

This is bad. Very bad.

irb(main):007:0> hash[:d] << “blah”
=> “blah”
irb(main):008:0> hash[:e] += " blah"
=> “blah blah”
irb(main):009:0> hash
=> {:b=>“nothing - two”, :e=>“blah blah”, :c=>“blah”, :a=>“test - one”}

Make sure you use the block form initializer whenever you have a mutable
default object.

On Fri, Dec 9, 2011 at 11:28 AM, Andrew S. [email protected]
wrote:

Hi there,

I have a hash with various keys and values that are strings.

If the key exists, the following works: h[“foo”] += “bar”


Posted via http://www.ruby-forum.com/.

You can have something like this to check whether the key is present or
not-

h[“key”] += value if h[“key”]

On Dec 8, 2011, at 23:06, Mayank K. [email protected]
wrote:

You can have something like this to check whether the key is present or
not-

h[“key”] += value if h[“key”]

Values can be false/nil.

On Fri, Dec 9, 2011 at 2:53 PM, Robert K.
[email protected]wrote:

h[“key”] += value if h[“key”]
irb(main):008:0> h[:f] += “bar”

Kind regards

robert


remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thanks for the enlightenment!!! Learned something about hashes today. :slight_smile:

On Fri, Dec 9, 2011 at 8:38 AM, Ryan D. [email protected]
wrote:

On Dec 8, 2011, at 23:06, Mayank K. [email protected] wrote:

You can have something like this to check whether the key is present or
not-

h[“key”] += value if h[“key”]

Values can be false/nil.

Also, this is inelegant. Either do this to prevent accidental
modification of the default object:

irb(main):006:0> h = Hash.new(“”.freeze)
=> {}
irb(main):007:0> h[:e] += “foo”
=> “foo”
irb(main):008:0> h[:f] += “bar”
=> “bar”
irb(main):009:0> h
=> {:e=>“foo”, :f=>“bar”}
irb(main):010:0> h[:f] += “foo”
=> “barfoo”
irb(main):011:0> h
=> {:e=>“foo”, :f=>“barfoo”}

Or, what I’d consider better because it is more efficient, use
String#<< to append and not create new instances all the time:

irb(main):012:0> h = Hash.new {|ha,k| h[k] = “”}
=> {}
irb(main):013:0> h[:e] << “foo”
=> “foo”
irb(main):014:0> h[:f] << “bar”
=> “bar”
irb(main):015:0> h
=> {:e=>“foo”, :f=>“bar”}
irb(main):016:0> h[:f] << “foo”
=> “barfoo”

Kind regards

robert

On Fri, Dec 9, 2011 at 11:22 AM, Mayank K.
[email protected] wrote:

Thanks for the enlightenment!!! Learned something about hashes today. :slight_smile:

You’re welcome. I just had one spelling error:

irb(main):012:0> h = Hash.new {|ha,k| h[k] = “”}

should have been

irb(main):012:0> h = Hash.new {|ha,k| ha[k] = “”}

It does not make a difference in this case (since ha == h) but the
corrected version is more robust (i.e. if someone reassigns h).

Kind regards

robert

Andrew S. wrote in post #1035841:

Hi there,

I have a hash with various keys and values that are strings.

If the key exists, the following works: h[“foo”] += “bar”

But if the key does not exist, I get an error.

Is it possible in one statement to cover both the cases where the key
does exist (as above) AND the case where the key does not exist - and in
this situation I’d like the new key and value pair to be created in the
hash.

Any help gratefully received!

  • A

see if this solves your problem:
=begin
One liner to update an hash of string values:
h[:key] = h.has_key?(:key) ? h[:key] += ‘-New_value’ : ‘First_value’
=end

h = {}
h[:foo] = h.has_key?(:foo) ? h[:foo] += ‘-foo_2nd’ : ‘foo_1st’
h[:bar] = h.has_key?(:bar) ? h[:bar] += ‘-bar_2nd’ : ‘bar_1st’
p 'From empty hash: ’ + h.inspect
h[:foo] = h.has_key?(:foo) ? h[:foo] += ‘-foo_2nd’ : ‘foo_1st’
h[:bar] = h.has_key?(:bar) ? h[:bar] += ‘-bar_2nd’ : ‘bar_1st’
p 'Updated hash…: ’ + h.inspect
exit(0)

=begin
Output:
“From empty hash: {:foo=>“foo_1st”- :bar=>“bar_1st”}”
“Updated hash…: {:foo=>“foo_1st-foo_2nd”-
:bar=>“bar_1st-bar_2nd”}”
=end
HTH gfb

Many thanks to all who replied!