# How to "New" an array of Hashes

**URL:** <https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634>\
**Category:** Rails\
**Created:** [September 3, 2007, 6:50am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634 "2007-09-03T06:50:26Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 6:50am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/1 "2007-09-03T06:50:26Z")

</div>

I am creatinig a “constant” array containing hashes. Then, in the  
code, I create a new array based on the constant array. The hashes in  
the new array are then manipulated in the code. Here is some psudo-  
code showing what I am doing.

TAB\_SET = [{}, {}, … {}]

def process\_tabset  
tabs = Array.new(TAB\_SET)  
\<Process the tabs array here, modifying the hash values as needed\>  
end

Apparently what happens is that the new array contains REFERENCES to  
the original hashes instead of separate copies. Whatever changes are  
made to hashes in the “tabs” array, also shows up in the hashes in the  
TAB\_SET array. In development mode (with config.cache\_classes = false)  
this doesn’t matter, as the whole thing gets re-initialized on the  
next call anyway. But in Production mode, this causes all sorts of  
problems.

How do I create the tabs array with copies of the hashes, instead of  
references back to the originals?

Thanks,  
sjf

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 7:03am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/2 "2007-09-03T07:03:27Z")

</div>

sjf\_control wrote:

> TAB\_SET = [{}, {}, … {}]
> 
> def process\_tabset  
> tabs = Array.new(TAB\_SET)  
> \<Process the tabs array here, modifying the hash values as needed\>  
> end
> 
> Apparently what happens is that the new array contains REFERENCES to  
> the original hashes instead of separate copies.  
> According to the pickaxe book it should be a copy. Perhaps try

tabs = Array.new.concat(TAB\_SET)

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 8:01am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/3 "2007-09-03T08:01:33Z")

</div>

TAB\_SET.dup

I won’t ask why you would actually want to do this.

Rein

On Sep 3, 12:02 am, Anthony R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 5:10pm UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/4 "2007-09-03T17:10:59Z")

</div>

On Sep 3, 12:02 am, Anthony R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> According to the pickaxe book it should be a copy. Perhaps try
> 
> tabs = Array.new.concat(TAB\_SET)

Nope – doesn’t work.

irb(main):001:0\> TAB\_SET = [{:one=\>“uno”},{:two=\>“dos”}]  
=\> [{:one=\>“uno”}, {:two=\>“dos”}]  
irb(main):002:0\> tabs = Array.new.concat(TAB\_SET)  
=\> [{:one=\>“uno”}, {:two=\>“dos”}]  
irb(main):003:0\> tabs[1][:two] += “(2)”  
=\> “dos(2)”  
irb(main):004:0\> tabs  
=\> [{:one=\>“uno”}, {:two=\>“dos(2)”}]  
irb(main):005:0\> TAB\_SET  
=\> [{:one=\>“uno”}, {:two=\>“dos(2)”}]  
irb(main):006:0\>

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 5:23pm UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/5 "2007-09-03T17:23:00Z")

</div>

On Sep 3, 1:00 am, removed\_email\_address@domain.invalid wrote:

> TAB\_SET.dup
> 
> I won’t ask why you would actually want to do this.

Well, why I would want to do this isn’t really relevant, unless you  
have a better way.

In short, each array entry contains information about a folder-tab on  
a page. One of the hashes contains the tab’s label, and I want to be  
able to dynamically update (append to) the label based on the contents  
of that page. In the example below, though, I would get “dos(2)” the  
first time (correct), and “dos(2)(2)” the second, and so forth.

But in any case, “dup” doesn’t work either…

irb(main):001:0\> TAB\_SET = [{:one=\>“uno”},{:two=\>“dos”}]  
=\> [{:one=\>“uno”}, {:two=\>“dos”}]  
irb(main):002:0\> tabs = TAB\_SET.dup  
=\> [{:one=\>“uno”}, {:two=\>“dos”}]  
irb(main):003:0\> tabs[1][:two] += “(2)”  
=\> “dos(2)”  
irb(main):004:0\> tabs  
=\> [{:one=\>“uno”}, {:two=\>“dos(2)”}]  
irb(main):005:0\> TAB\_SET  
=\> [{:one=\>“uno”}, {:two=\>“dos(2)”}]

I believe the problem is NOT that the array is a reference. Using  
either “new” or “dup” should get me a fresh array. The problem is that  
the array ELEMENTS (the hashes) are references back to the original  
hashes. So I’m guessing I need something like:

tabs = Array.new( Hash.new(hash1), Hash.new(hash2), … )  
But that sure isn’t very pretty!

Anybody know an easier way?

sjf

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 3, 2007, 8:30pm UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/6 "2007-09-03T20:30:46Z")

</div>

In a situation like this, where you are using basic data structures  
and defining all this business logic external to them to control their  
use, the ruby way would be to encapsulate all this logic in a class  
and use it like:

@tabs = TabSet.new( options )

This way your TabSet class encapsulates all the logic of initializing  
and controlling a set of tabs (whatever that may be). You can use  
intention-revealing methods on that class and its instances to achieve  
its goals.

Otherwise, and I hesitate to suggest this for fear that you might  
actually do it, you would need a deep copy:

@tabs = Marshal.load(Marshal.dump(TAB\_SET))

But please please please please don’t actually do that. It’s ugly as  
all hell.

Rein

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 4, 2007, 4:25am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/7 "2007-09-04T04:25:42Z")

</div>

The issue that you are running into here is one of scope. Since  
TAB\_SET is the same across all instances of the class, modifying it  
will modify all variables that point to it. The point of using a class  
is that you can change the implementation to be more robust, not just  
to wrap your current implementation inside a class.

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 4, 2007, 3:29am UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/8 "2007-09-04T03:29:35Z")

</div>

Rein

Thanks for sticking with this subject.  
I am sure I am missing your point here. The problem exists whether the  
code is in a separate class or not. As a test I added the file  
tab\_set.rb to my models. It contains…

class TabSet

TAB\_SET = [{:label=\>“one”}, {:label=\>“two”}]

def initialize  
@a = Array.new(TAB\_SET)  
end

def process  
@a[1][:label] = TAB\_SET[1][:label] + “(2)” # grab the original  
value and append a string  
@a  
end  
end

I then run it from the console…

> > a = TabSet.new  
> > =\> #\<TabSet:0x36caf40 @a=[{:label=\>“one”}, {:label=\>“two”}]\>
> 
> > b = a.process  
> > =\> [{:label=\>“one”}, {:label=\>“two(2)”}]
> 
> > b = a.process  
> > =\> [{:label=\>“one”}, {:label=\>“two(2)(2)”}]

in fact, its even worse – since if I now try to NEW another tabset…

> > c=TabSet.new  
> > =\> #\<TabSet:0x36c7048 @a=[{:label=\>“one”}, {:label=\>“two(2)(2)”}]\>

What did I miss?

Thanks,  
sjf

---

<div class="post-metadata">

**Author:** ![sjf\_control](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c68b51/32.png) [@sjf\_control](https://www.ruby-forum.com/u/sjf_control)\
**Post date:** [September 4, 2007, 12:23pm UTC](https://www.ruby-forum.com/t/how-to-new-an-array-of-hashes/113634/9 "2007-09-04T12:23:38Z")

</div>

This isn’t that pretty either but you could possibly do:

tabs = TAB\_SET.dup.map(&:dup)
