[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Hash default value question

Glenn

9/19/2008 5:40:00 PM

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 <w_a_x_man@yahoo.com>=0ATo: ruby-talk ML <ruby-talk@ruby-lang.org>=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 <glenn_r...@yahoo.com> 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 [i] }=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
2 Answers

Todd Benson

9/19/2008 6:33:00 PM

0

On Fri, Sep 19, 2008 at 12:40 PM, Glenn <glenn_ritz@yahoo.com> 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

> 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

Rob Biedenharn

9/19/2008 6:41:00 PM

0

On Sep 19, 2008, at 1:40 PM, Glenn 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.)
>
> 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 <w_a_x_man@yahoo.com>
> To: ruby-talk ML <ruby-talk@ruby-lang.org>
> 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 <glenn_r...@yahoo.com> wrote:
>> [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] = [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

Rob Biedenharn http://agileconsult...
Rob@AgileConsultingLLC.com
+1 513-295-4739
Skype: rob.biedenharn