From: Edmond Kachale Date: 2011-10-27T17:53:35+09:00 Subject: Re: Unusual behavior of a Ruby hash --0016364ef4aa48eca604b043e893 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable In fact, Jesus should be the program saviour (i'm kidding). 2011/10/25 Jes=FAs Gabriel y Gal=E1n > Well, first of all, it seems that essential_params has a key :params_hash= , > so I guess it's something like: > > essential_params =3D {:params_hash =3D> {:val_1 =3D> 0, :val_2 =3D> [x,y,= z], > :val_3 =3D>0}} > I agree. In fact, :params_hash in essential_params is an array of hashes. So, modify your line 15 to this: > > new_data[:params_hash] =3D essential_params[:params_hash].dup > > and let us know if it worked for you. > > Hope this helps, > I should say, it took me this long to get all this was getting messed up. A= s it was rightly put by Jesus, I needed to duplicate essential_params[:params_hash]. Since essential_params[:params_hash] is als= o an array of hashes, at every iteration I have to duplicate each hash elemen= t of the "essential_params[:params_hash]" array. Though I do not love the repetitive "semi-manual" duplication, but it is much more efficient than th= e repetitive database querying. In due course, I have learned two good methods and their differences: *clon= e * and *dup* ( http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/6326). Thanks folks!! --- *Edmond* 2011/10/25 Jes=FAs Gabriel y Gal=E1n > On Tue, Oct 25, 2011 at 3:50 PM, Edmond Kachale > wrote: > > Rubysters, > > > > I had the following code working nicely: > > > > (a) http://pastie.org/private/8qn4f36mfeppbobm7b2wsa > > > > At the beginning of every iteration, I expect "essential_params" hash (= in > > line 8) to look like this: essential_params =3D {:val_1 =3D> 0, :val_2= =3D> > > [x,y,z], :val_3 =3D>0}. However it does repetitive work to initialize a > hash > > from a database (in line 8). > > > > So as to reduce repetitive database querying (at every iteration), I ha= ve > > just moved hash initialization to (line 7) outside a loop: > > > > (b) http://pastie.org/private/iudfe0q2s41vszxby6vva > > > > Now the code acts wierd: At every iteration, my "essential_params" has= h > > contains data accumulated from the previous iterations. For example, at > the > > nth iteration, essential_params may look like this: {:val_1 =3D> 25, :v= al_2 > =3D> > > [x,y,z], :val_3 =3D>24} which are results from (n-1)th iteration (inste= ad > of > > the default values: {:val_1 =3D> 0, :val_2 =3D> [x,y,z], :val_3 =3D>0})= . > > > > Well, first of all, it seems that essential_params has a key > :params_hash, so I guess it's something like: > > essential_params =3D {:params_hash =3D> {:val_1 =3D> 0, :val_2 =3D> [x,y,= z], > :val_3 =3D>0}} > > If this is the case, then you are overwriting the values of the > params_hash in lines 22 and 23. When you do this: > > new_data[:params_hash] =3D essential_params[:params_hash] > > you are referencing one hash (essential_params[:params_hash]) from the > other hash. So when, after that, you do this: > > new_data[:params_hash][:val_1] =3D 25 > > you are changing the original hash object. > > > Does anyone have a better explanation about this? Are Ruby hashed > assigned > > by value or by reference? (Specifically, why is the pre-populated hash = at > > line 7 in (b) getting values from lines 22 and 23 ? ) > > Everything in Ruby is an object. When you assign to a variable, you > are making the variable reference the object. When you call a method > through the variable, you are sending that message to the object. An > object can be referenced by several variables. Check this: > > ruby-1.8.7-p334 :001 > a =3D {} > =3D> {} > ruby-1.8.7-p334 :002 > a.object_id > =3D> -611696338 > ruby-1.8.7-p334 :003 > b =3D a > =3D> {} > ruby-1.8.7-p334 :004 > b.object_id > =3D> -611696338 > > Both a and b are variables that point to the same object. There's only > one hash. So when you change the hash, be it through a or through b > you are changing the same object: > > ruby-1.8.7-p334 :005 > b[:val] =3D 3 > =3D> 3 > ruby-1.8.7-p334 :006 > a > =3D> {:val=3D>3} > > This is basically what you are seeing in your code (a is > essential_params[:params_hash] and b is new_data[:params_hash]). > You might want to create a copy of the hash so that the original hash > is not modified. You can do that with Object#dup. > > ruby-1.8.7-p334 :007 > a =3D {:val =3D> 3} > =3D> {:val=3D>3} > ruby-1.8.7-p334 :008 > b =3D a.dup > =3D> {:val=3D>3} > ruby-1.8.7-p334 :009 > b[:val] =3D 5 > =3D> 5 > ruby-1.8.7-p334 :010 > a > =3D> {:val=3D>3} > ruby-1.8.7-p334 :011 > b > =3D> {:val=3D>5} > > So, modify your line 15 to this: > > new_data[:params_hash] =3D essential_params[:params_hash].dup > > and let us know if it worked for you. > > Hope this helps, > > Jesus. > > --0016364ef4aa48eca604b043e893--