FAQ? Hash concatenation

I've read matz's explanation for the lack of a concatenation operator for
Hashes in Ruby, but I was wondering if there were a module that supplied one
anyway. Or at least a self-modifying method that works like update() but
without clobbering existing values.

It's easy enough to write my own, but if there's one in the standard library or
on RAA module I'd rather use that.

Thanks for any help.

myhash['keyval'] ||= newval ## won't stomp on existing value if
'keyval' already in my #keys

also, Hash#merge and Hash#merge! take blocks to say how to handle
duplicated key values

Hi Mark,

I was wondering if there were a module that supplied [...]
a self-modifying method that works like update() but
without clobbering existing values.

Here's what I use, FWIW:

   def compensate(defaults)
     defaults.merge self
   end

   def compensate!(defaults)
     for key, value in defaults do
       self[key] = value unless include? key
     end
   end

I mostly use these methods to provide defaults for options
that are passed in a hash.

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.

Mark J. Reed wrote:

I've read matz's explanation for the lack of a concatenation operator for
Hashes in Ruby, but I was wondering if there were a module that supplied one
anyway. Or at least a self-modifying method that works like update() but
without clobbering existing values.

h={'a',1, 'c',3, 'd',4}
h={'a',99, 'b',2}.update(h)
  --> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

Hi --

Mark J. Reed wrote:

I've read matz's explanation for the lack of a concatenation operator for
Hashes in Ruby, but I was wondering if there were a module that supplied one
anyway. Or at least a self-modifying method that works like update() but
without clobbering existing values.

h={'a',1, 'c',3, 'd',4}
h={'a',99, 'b',2}.update(h)
--> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

However....

irb(main):006:0> h={'a',1, 'c',3, 'd',4}
=> {"a"=>1, "c"=>3, "d"=>4}
irb(main):007:0> h.object_id
=> 537888058
irb(main):008:0> h={'a',99, 'b',2}.update(h)
=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4}
irb(main):009:0> h.object_id
=> 537863828

So if it matters that it be the same object, this technique won't be
appropriate. Also, if you're using something other than a hash
literal, for example:

   h1 = h2.update(h1)

you're going to change h2, which might also be undesireable in some
cases.

David

···

On Sat, 23 Jul 2005, William James wrote:

--
David A. Black
dblack@wobblini.net

Hi --

Hi Mark,

I was wondering if there were a module that supplied [...]
a self-modifying method that works like update() but
without clobbering existing values.

Here's what I use, FWIW:

  def compensate(defaults)
    defaults.merge self
  end

I'm curious what this gains you. Is it better than just saying
defaults.merge(self)?

  def compensate!(defaults)
    for key, value in defaults do
      self[key] = value unless include? key
    end
  end

That one seems to do more :slight_smile:

David

···

On Sat, 23 Jul 2005, Daniel Brockman wrote:

--
David A. Black
dblack@wobblini.net

myhash['keyval'] ||= newval ## won't stomp on existing value if
'keyval' already in my #keys

Though beware of nil and false

irb(main):001:0> h = {1 => nil, 2 => false, 3 => true}
=> {1=>nil, 2=>false, 3=>true}
irb(main):002:0> h[1] ||= 2
=> 2
irb(main):003:0> h[2] ||= 3
=> 3
irb(main):004:0> h[4] ||= 5
=> 5
irb(main):005:0> h
=> {1=>2, 2=>3, 3=>true, 4=>5}

regards,

Brian

···

On 23/07/05, Gene Tani <gene.tani@gmail.com> wrote:

also, Hash#merge and Hash#merge! take blocks to say how to handle
duplicated key values

--
http://ruby.brian-schroeder.de/

Stringed instrument chords: http://chordlist.brian-schroeder.de/

David A. Black wrote:

   h1 = h2.update(h1)

you're going to change h2, which might also be undesireable in some
cases.

h=h2.dup.update(h)

"David A. Black" <dblack@wobblini.net> writes:

  def compensate(defaults)
    defaults.merge self
  end

I'm curious what this gains you. Is it better than just
saying defaults.merge(self)?

Good point. Come to think about it, I doubt if I ever used
the non-destructive variant. I guess depending on your
taste it could be nicer when defaults is a hash literal and
self isn't.

   def foo1(options)
     bar { :moomin => 123 }.merge(options)
   end

   def foo2(options)
     bar options.compensate(:moomin => 123)
   end

The former is shorter and uses standard operations only,
but the latter is arguably conceptually simpler once you
get used to the compensate method.

Also, you could argue that if there's a ‘compensate!’,
then there should also be a ‘compensate’.

But yeah... :slight_smile:

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.

William James wrote:

David A. Black wrote:

> h1 = h2.update(h1)
>
> you're going to change h2, which might also be undesireable in some
> cases.

h=h2.dup.update(h)

I guess this should be
h=h2.merge(h)

Hi --

···

On Sat, 23 Jul 2005, William James wrote:

William James wrote:

David A. Black wrote:

   h1 = h2.update(h1)

you're going to change h2, which might also be undesireable in some
cases.

h=h2.dup.update(h)

I guess this should be
h=h2.merge(h)

And if you want to keep h the same object:

   h.replace(h2.merge(h))

David

--
David A. Black
dblack@wobblini.net