Hi –
OK, I’m messing around with hashes for the first time,
and I’ve hit a (very) small bump.
Let’s say I have a an array where each line contains
key=value. Also, assume that there can be duplicate
keys and if so, the final ‘value’ should be an array.
In theory, I’d like to ‘each’ through the array and
fill the hash like this…
foo = Hash.new
data.each {|line|
line =~ /^(.)=(.)$/
key, value = $1.split, $2.split # so far, so good
foo[key].push(value)
}
Now, there are two problems with this.
(1) << (or .push) doesn’t change the array… I have
to do foo[key] = foo[key].push(value). This is ok,
but wouldn’t it make sense to have <<= or .push!
methods? But this is completeness stuff and obviously
not a priority for Matz.
<< and push do change the array. If they don’t seem to, then
something else is wrong. A method called push! would make no sense,
since push already modifies the receiver, and the ! is a clue that
this is a method which modifies the receiver in a case where there’s a
!-less version that doesn’t.
(2) << (or .push) doesn’t know what to do if foo[key]
is nil (since it doesn’t know it’s of type Array). No
Yes, they do know what to do: raise an exception
Or,
more precisely, an object that doesn’t respond to << or
push knows to raise an exception.
problem, I think to myself… I’ll just declare foo as
foo=Hash.new(). Of course, this doesn’t work since
now, ALL keys point to the SAME array… if I modify
I think there’s a capacity in 1.7.x to create a hash with
a default proc that gets called each time, instead of a
static default. (I can never seem to remember the status
of that, but I think it’s there, or coming.)
one, I modify all of them…doh! I know I COULD do a
check to see if the value is nil or not, but that gets
a little messy. I guess what would be nice is if I
could specify that this is a Hash of Arrays (or
whatever) during instantiation without the defining of
a default value… something like foo=Hash.new(Array).
Anyone have a better solution?
This might be useable or give you some ideas (in the absence of the
dynamic hash default mentioned above):
data = <<EOS
one=un
one=eins
two=deux
two=zwei
two=due
three=trois
EOS
h = Hash.new
data.each do |line|
k,v = line.split(/=/)
h[k] ||= Array.new
h[k].push(v)
end
p h # nice hash of all those things 
The key here is:
h[k] ||= Array.new
which basically means: if h[k] is nil, assign a new array to
it. If it isn’t nil, leave it alone.
You could even combine the last two lines into:
(h[k] ||= Array.new).push(v)
which is actually a fairly common idiom.
David
···
On Fri, 6 Dec 2002, Jason Persampieri wrote:
–
David Alan Black
home: dblack@candle.superlink.net
work: blackdav@shu.edu
Web: http://pirate.shu.edu/~blackdav