Hashtable of sets

T

Trevor Harmon

Hi,

I'm new to Ruby and need a data structure that consists of a hashtable
of sets. While writing some code for this, I've run into some odd Ruby
behavior that I'm hoping someone can explain to me.

I started with a hashtable:

h = Hash.new([])

Here, I made the default value an empty set instead of nil. That way,
if I wanted to add a new element "q" to a set mapped to the key 'a', I
could do so in just one line. For example:

h['a'] = %w{q r s}
h['a'] << "t"

That seemed to work:
h['a'] => ["q", "r", "s", "t"]
h['b']
=> []

Great! Now let me add an element to the set mapped to 'b':

h['b'] << "x"

That seemed to work, too:
=> ["x"]

But wait, now all the other keys are mapped to the same thing!
h['c'] => ["x"]
h['d']
=> ["x"]

Can someone please explain how this happened? I don't understand it. Thanks,

Trevor

P.S. I'm using Ruby 1.8.4.
 
M

Marcin Mielżyński

Trevor said:
Hi,

I'm new to Ruby and need a data structure that consists of a hashtable
of sets. While writing some code for this, I've run into some odd Ruby
behavior that I'm hoping someone can explain to me.

I started with a hashtable:

h = Hash.new([])

This supplies the default object value when there is no key in a hash
and this object will not be copied, so:

h['foo'] << 4
h['blah'] << "ddd"
=> [4, "ddd"]

the same instance is referenced...

In order to create a hash that behaves the way you expect, is to create
a hash with a block that returns default value (in this case a separate
instance will be created):


h = Hash.new{[]}
h['foo'] << 4
h['blah'] << "ddd"
=> []

lopex
 
T

Trevor Harmon

In order to create a hash that behaves the way you expect, is to create
a hash with a block that returns default value (in this case a separate
instance will be created):

h = Hash.new{[]}
h['foo'] << 4
h['blah'] << "ddd"
=> []

That fixes the same-instance problem, but it still doesn't work right
because h['foo'] and h['blah'] also return [].

I could fix this by special-handling the case where the hashtable entry
is empty, but that would defeat the purpose of the Hash.new{[]} trick.
Isn't there some one-liner I could use to add elements to this data
structure? Thanks,

Trevor
 
R

Robert Klemme

Marcin said:
Trevor said:
Hi,

I'm new to Ruby and need a data structure that consists of a hashtable
of sets. While writing some code for this, I've run into some odd Ruby
behavior that I'm hoping someone can explain to me.

I started with a hashtable:

h = Hash.new([])

This supplies the default object value when there is no key in a hash
and this object will not be copied, so:

h['foo'] << 4
h['blah'] << "ddd"
=> [4, "ddd"]

the same instance is referenced...
Correct.

In order to create a hash that behaves the way you expect, is to create
a hash with a block that returns default value (in this case a separate
instance will be created):


h = Hash.new{[]}
h['foo'] << 4
h['blah'] << "ddd"
=> []

No, you need this

require 'set'
h = Hash.new {|ha,k| ha[k] = Set.new}

1. Class Set implements the requirement of Trevor who wants a hash of sets.

2. Assignment is needed in the block because otherwise a new Set / Array
is returned every time a key is not found.

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top