Hash default value question

G

Glenn

Hi,=0A=0ACan anyone explain why hash_of_indexes1 in the code below works, b=
ut hash_of_index2 doesn't?=A0 (I got the first method as a response to a pr=
evious post.)=0A=0AWhat 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.=A0 The first method works, but the second one doesn'=
t.=A0 I figured if I created the hash in the second method with a default v=
alue of an empty array, h[e.to_f] in the each method of the hash would retu=
rn=A0an empty array the first time it sees each key.=A0 But what=A0actually=
=A0happens is that the values for all of the keys are the same when the has=
h's each method finishes --=A0each value is=A0an array with all of the inde=
x values in the receiver array.=0A=0Aclass Array=0A=A0 def hash_of_indexes1=
=0A=A0=A0=A0 h =3D Hash.new=0A=A0=A0=A0 each_with_index { |e, i| h[e.to_f] =
=3D Array( h[e.to_f] ) << i }=0A=A0=A0=A0 h=0A=A0 end=0A=0A=A0 def hash_of_=
indexes2=0A=A0=A0=A0 h =3D Hash.new([])=0A=A0=A0=A0 each_with_index { |e, i=
| h[e.to_f] =3D h[e.to_f] << i }=0A=A0=A0=A0 h=0A=A0 end=0Aend=0A=0A[1, 2, =
2, 3].hash_of_indexes1.inspect ## --> returns {1.0=3D>[0], 3.0=3D>[3], 2.0=
=3D>[1, 2]}=0A=0A[1, 2, 2, 3].hash_of_indexes2.inspect ## --> returns {1.0=
=3D>[0, 1, 2, 3], 3.0=3D>[0, 1, 2, 3], 2.0=3D>[0, 1, 2, 3]}=0A=0AThanks for=
your help.=0A=0A=0A=0A=0A=0A----- Original Message ----=0AFrom: William Ja=
mes <[email protected]>=0ATo: ruby-talk ML <[email protected]>=0ASe=
nt: Sunday, September 14, 2008 4:02:54 PM=0ASubject: Re: Passing a method c=
all into a method=0A=0AOn Sep 14, 8:18 am, Glenn <[email protected]> wro=
te:=0A> [Note:=A0 parts of this message were removed to make it a legal pos=
t.]=0A>=0A> Hi,=0A>=0A> I am trying to figure out how to pass a method call=
into a method.=0A>=0A> I wrote a generic method that call be called on an =
array of numbers, and returns an array of the index values in the receiver =
that meet a specified condition:=0A>=0A> class Array=0A>=A0 def hash_of_ind=
exes=0A>=A0 =A0 if self.empty?=0A>=A0 =A0 =A0 'The array is empty.'=0A>=A0 =
=A0 else=0A>=A0 =A0 =A0 h =3D {}=0A>=A0 =A0 =A0 self.each_with_index { |e, =
i| h.include?(e.to_f) ? h[e.to_f] << i : h[e.to_f] =3D }=0A>=A0 =A0 =A0=
h=0A>=A0 =A0 end=0A>=A0 end=0A=0A=0Aclass Array=0A=A0 def hash_of_indexes=
=0A=A0 =A0 h =3D {}=0A=A0 =A0 each_with_index{ |e,i|=0A=A0 =A0 =A0 e =3D e.=
to_f=0A=A0 =A0 =A0 h[e] =3D Array( h[e] ) << i }=0A=A0 =A0 h=0A=A0 end=0Aen=
d
 
T

Todd Benson

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

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]}

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
 
R

Rob Biedenharn

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.

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
----- Original Message ----
From: William James <[email protected]>
To: ruby-talk ML <[email protected]>
Sent: Sunday, September 14, 2008 4:02:54 PM
Subject: Re: Passing a method call into a method

[Note: parts of this message were removed to make it a legal post.]

Hi,

I am trying to figure out how to pass a method call into a method.

I wrote a generic method that call be called on an array of
numbers, and returns an array of the index values in the receiver
that meet a specified condition:

class Array
def hash_of_indexes
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] = }
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


Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
+1 513-295-4739
Skype: rob.biedenharn
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top