# Hash default value question

**URL:** <https://www.ruby-forum.com/t/hash-default-value-question/149049>\
**Category:** Ruby\
**Created:** [September 19, 2008, 8:29pm UTC](https://www.ruby-forum.com/t/hash-default-value-question/149049 "2008-09-19T20:29:30Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![glenn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/4bbf92/32.png) [@glenn](https://www.ruby-forum.com/u/glenn)\
**Post date:** [September 19, 2008, 8:29pm UTC](https://www.ruby-forum.com/t/hash-default-value-question/149049/1 "2008-09-19T20:29:30Z")

</div>

Hi,

Can anyone explain why hash\_of\_indexes1 in the code below works, but  
hash\_of\_index2 doesn’t?Â (I got the first method as a response to a  
previous post.)

What I’d like to get is a hash with a key value for each unique value in  
the receiver array, and I’d like the value for each key to be an array  
of integers corresponding to the index values of the elements in the  
original array.Â The first method works, but the second one doesn’t.Â I  
figured if I created the hash in the second method with a default value  
of an empty array, h[e.to\_f] in the each method of the hash would  
returnÂ an empty array the first time it sees each key.Â But  
whatÂ actuallyÂ happens is that the values for all of the keys are the  
same when the hash’s each method finishes --Â each value isÂ an array with  
all of the index values in the receiver array.

class Array  
Â def hash\_of\_indexes1  
Â Â Â h = Hash.new  
Â Â Â each\_with\_index { |e, i| h[e.to\_f] = Array( h[e.to\_f] ) \<\< i }  
Â Â Â h  
Â end

Â def hash\_of\_indexes2  
Â Â Â h = Hash.new([])  
Â Â Â each\_with\_index { |e, i| h[e.to\_f] = h[e.to\_f] \<\< i }  
Â Â Â h  
Â end  
end

[1, 2, 2, 3].hash\_of\_indexes1.inspect ## → returns {1.0=\>[0],  
3.0=\>[3], 2.0=\>[1, 2]}

[1, 2, 2, 3].hash\_of\_indexes2.inspect ## → returns {1.0=\>[0, 1, 2, 3],  
3.0=\>[0, 1, 2, 3], 2.0=\>[0, 1, 2, 3]}

Thanks for your help.

----- Original Message ----  
From: William J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
To: ruby-talk ML [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Sent: Sunday, September 14, 2008 4:02:54 PM  
Subject: Re: Passing a method call into a method

On Sep 14, 8:18 am, Glenn [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Â Â if self.empty?  
> Â Â Â ‘The array is empty.’  
> Â Â else  
> Â Â Â h = {}  
> Â Â Â self.each\_with\_index { |e, i| h.include?(e.to\_f) ? h[e.to\_f] \<\< i : h[e.to\_f] = [i] }  
> Â Â Â h  
> Â Â end  
> Â end

class Array  
Â def hash\_of\_indexes  
Â Â h = {}  
Â Â each\_with\_index{ |e,i|  
Â Â Â e = e.to\_f  
Â Â Â h[e] = Array( h[e] ) \<\< i }  
Â Â h  
Â end  
end

---

<div class="post-metadata">

**Author:** ![glenn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/4bbf92/32.png) [@glenn](https://www.ruby-forum.com/u/glenn)\
**Post date:** [September 19, 2008, 8:49pm UTC](https://www.ruby-forum.com/t/hash-default-value-question/149049/2 "2008-09-19T20:49:35Z")

</div>

On Sep 19, 2008, at 1:40 PM, Glenn wrote:

> second one doesn’t. I figured if I created the hash in the second  
> each\_with\_index { |e, i| h[e.to\_f] = Array( h[e.to\_f] ) \<\< i }  
> [1, 2, 2, 3].hash\_of\_indexes1.inspect ## → returns {1.0=\>[0],  
> 3.0=\>[3], 2.0=\>[1, 2]}
> 
> [1, 2, 2, 3].hash\_of\_indexes2.inspect ## → returns {1.0=\>[0, 1, 2,  
> 3], 3.0=\>[0, 1, 2, 3], 2.0=\>[0, 1, 2, 3]}
> 
> Thanks for your help.

The Hash.new([]) causes a single array to be used (shared) for the  
default value. Using the block form, Hash.new {[]}, would produce the  
behavior you want. It’s common to see this used as:  
Hash.new {|h,k| h[k] = [] }  
if you want the key to exist in the hash when referenced (as you seem  
to expect here).

class Array  
def hash\_of\_indexes3  
h = Hash.new {|h,k| h[k] = []}  
each\_with\_index {|e,i| h[e] \<\< i }  
h  
end  
end  
irb\> [1, 2, 2, 3].hash\_of\_indexes3  
=\> {1=\>[0], 2=\>[1, 2], 3=\>[3]}

I’m not sure why you wanted to call .to\_f on each element, I left that  
out.

-Rob

> > ```
> > else
> > 
> > ```
> 
> ```
> h = {}
> each_with_index{ |e,i|
> e = e.to_f
> h[e] = Array( h[e] ) << i }
> h
> 
> ```
> 
> end  
> end

Rob B. [http://agileconsultingllc.com](http://agileconsultingllc.com)  
removed\_email\_address@domain.invalid  
+1 513-295-4739  
Skype: rob.biedenharn

---

<div class="post-metadata">

**Author:** ![glenn](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/4bbf92/32.png) [@glenn](https://www.ruby-forum.com/u/glenn)\
**Post date:** [September 19, 2008, 9:19pm UTC](https://www.ruby-forum.com/t/hash-default-value-question/149049/3 "2008-09-19T21:19:03Z")

</div>

On Fri, Sep 19, 2008 at 12:40 PM, Glenn [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hi,
> 
> Can anyone explain why hash\_of\_indexes1 in the code below works, but hash\_of\_index2 doesn’t? (I got the first method as a response to a previous post.)

snip

> ```
> h
> 
> ```
> 
> end  
> end
> 
> [1, 2, 2, 3].hash\_of\_indexes1.inspect ## → returns {1.0=\>[0], 3.0=\>[3], 2.0=\>[1, 2]}
> 
> [1, 2, 2, 3].hash\_of\_indexes2.inspect ## → returns {1.0=\>[0, 1, 2, 3], 3.0=\>[0, 1, 2, 3], 2.0=\>[0, 1, 2, 3]}

With hash\_of\_indexes2, the array assigned to the each hash key is the  
same Array object. You can tell this by comparing their **id** tags  
(apologies for lazy style)…

a = 1,2,3,4  
b = 1,2,3,4

a == b  
=\> true  
a. **id** == b. **id**  
=\> true

a = Array([1,2,3,4])  
b = Array([1,2,3,4])

a == b  
=\> true  
a. **id** == b. **id**  
=\> false

Todd
