Stefan Lang
2/28/2009 10:29:00 PM
2009/2/28 AD60 <andredeen@gmail.com>:
> Hi,
>
> I am puzzled by the workings a the following program. I placed the
> output after the corresponding lines. To me it lookes like a sort of
> bug in the workings of de p method. Can anybody set me straight?
There's no bug involved.
> h = Hash.new([])
Here you create Hash with an empty array as
default value. For every lookup of a key that is
not in the hash, this single array instance is
returned, but not automatically stored in the hash.
Again: It's a single object, not a new one on every
lookup.
> h[0] = [1,2,3]
Here you associate 0 with an array. The hash default
value is not involved.
> p h #> {0=>[1, 2, 3]}
> h[0] += [4]
> p h #> {0=>[1, 2, 3, 4]}
This is a syntactic shortcut for "h[0] = h[0] + [4]".
It looks up the value of 0 in the hash, which is
an array. array + array creates a new array,
which overwrites the previous value of h[0].
> h[1] += [10,11]
> p h #> {0=>[1, 2, 3, 4], 1=>[10, 11]}
Again, this is a shortcut for "h[1] = h[1] + [10, 11]".
The hash doesn't have a value for 1 yet, so
the default value ([]) is returned. [] + [10, 11] is
the new array [10, 11] which is then assigned
to h[1].
> h[1] << 12
> p h #> {0=>[1, 2, 3, 4], 1=>[10, 11, 12]}
Look up the existing array stored in h[1] and append
12. No new array created.
> h[2] << 20
> p h #> {0=>[1, 2, 3, 4], 1=>[10, 11, 12] ?
The hash doesn't have a value for 2, so the default
value, [], is returned. The default value is destructively
modified by appending 20. _No new hash entry is
created (there is no assignment!)._
Future lookups of non-existent keys will return
the modified default value!
> p h[2] #> [20] ???
The hash still doesn't have an entry for 2, so
the default value is returned, which by now is
our modified array.
> h[2] << 21
> p h #> {0=>[1, 2, 3, 4], 1=>[10, 11, 12]} ?
Still no entry for 2, default value is returned and modified
by appending 21.
> h[2] += [22]
> p h #> {0=>[1, 2, 3, 4], 1=>[10, 11, 12], 2=>[20, 21, 22]} ????????
Again, this is equivalent to "h[2] = h[2] + [22]".
Still no entry for h[2], so the default value is returned,
which by now is [20, 21]. Then the two arrays
[20, 21] and [22] are concatenated, returning the
new array [20, 21, 22] which is then finally associated
with 2 in the hash (see: here is an assignment!).
What you probably want to achieve can be
done using Hash's block constructor:
h = Hash.new { |hash, key| hash[key] = [] }
This automatically stores a new empty array
on every lookup of a non-existent key.
HTH,
Stefan