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

···

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

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

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

$ 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"}

···

--
   WBR, Peter Zotov.

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 Dec 8, 2011, at 21:58 , Andrew S. wrote:

I guess you could get really ugly with it.

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

···

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

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.

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

h["key"] += value if h["key"]

···

On Fri, Dec 9, 2011 at 11:28 AM, Andrew S. <andrewinfosec@gmail.com> 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"

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

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

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
# <test>
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)
# </test>
=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

···

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

Many thanks to all who replied!

···

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

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 Dec 8, 2011, at 22:03 , Peter Zotov wrote:

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

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

$ 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"}

Values can be false/nil.

···

On Dec 8, 2011, at 23:06, Mayank Kohaley <mayank.kohaley@gmail.com> wrote:

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

h["key"] += value if h["key"]

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 9, 2011 at 12:11 AM, Ryan Davis <ryand-ruby@zenspider.com>wrote:

On Dec 8, 2011, at 22:03 , Peter Zotov wrote:

> Andrew S. писал 09.12.2011 09:58:
>> 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
>
> $ 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"}

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.

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 8:38 AM, Ryan Davis <ryand-ruby@zenspider.com> wrote:

On Dec 8, 2011, at 23:06, Mayank Kohaley <mayank.kohaley@gmail.com> 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.

--
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 2:53 PM, Robert Klemme <shortcutter@googlemail.com>wrote:

On Fri, Dec 9, 2011 at 8:38 AM, Ryan Davis <ryand-ruby@zenspider.com> > wrote:
>
>
> On Dec 8, 2011, at 23:06, Mayank Kohaley <mayank.kohaley@gmail.com> > 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

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

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

···

On Fri, Dec 9, 2011 at 11:22 AM, Mayank Kohaley <mayank.kohaley@gmail.com> wrote:

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

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