# Changing an array data structure

**URL:** <https://www.ruby-forum.com/t/changing-an-array-data-structure/127045>\
**Category:** Ruby\
**Created:** [January 24, 2008, 4:05pm UTC](https://www.ruby-forum.com/t/changing-an-array-data-structure/127045 "2008-01-24T16:05:50Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 24, 2008, 4:05pm UTC](https://www.ruby-forum.com/t/changing-an-array-data-structure/127045/1 "2008-01-24T16:05:50Z")

</div>

Hello.

I already asked about how I’d best re-order a datastructure. But  
thinking about, I changed my mind; instead of the hash approach  
I’ve shown in news:removed\_email\_address@domain.invalid,  
I now think I might use arrays instead. Reason: The order in which  
something is inserted and later fetched is important to me. With  
Hashes in 1.8, this cannot easily be done out-of-the-box, can it?

Anyway - I’m now looking for a way to change the following arry:

timing = [  
[“Performance Test of Item Access using Lists”, [  
[[“Plants”, 100], [“Customers”, 50], [“Total”, 150]],  
[[“Plants”, 85], [“Customers”, 60], [“Total”, 145]],  
[[“Plants”, 111], [“Customers”, 77], [“Total”, 188]]  
]],  
[“Performance Test of Item Access using Advance Item Search”, [  
[[“Work List”, 17], [“Bookmarks”, 30], [“Total”, 42]],  
[[“Work List”, 10], [“Bookmarks”, 33], [“Total”, 50]],  
[[“Work List”, 22], [“Bookmarks”, 27], [“Total”, 99]]  
]]  
]

# This should become:

timing\_reordered = [  
[“Performance Test of Item Access using Lists”, [  
[“Plants”, [100, 85, 111]], [“Customers”, [50, 60, 77]],  
[“Total”, [150, 145, 188]]  
]],  
[“Performance Test of Item Access using Advance Item Search”, [  
[“Work List”, [17, 10, 22]], [“Bookmarks”, [30, 33, 27]],  
[“Total”, [42, 50, 99]]  
]]  
]

It very much resembles the datastructure shown in the hash approach.  
That’s only natural, if you take into consideration how the data is  
generated. To do that, I’m running a method 3 (or more) times; these  
methods generate the “Performance Test of Item Access using Lists”  
and “Performance Test of Item Access using Advance Item Search” data.  
These methods generate data; data items for Plants, Customers and  
so on.

But for reporting, it’s best for me, if all the eg. Plants results  
are “grouped together”. Actually, I only need the innermost arrays,  
ie. [100, 85, 111], [50, 60, 77], … These arrays should be  
concated, so that I’ve only got one long array, starting with: [100,  
85, 111, 50, 60, 77, …].

Well - how would I reorder the array best? I tried:

```
    timing.each { |test|
      ...
    }

```

But actually, I already fail to go on there. Now “test” is an array.  
When I access test[0], I get the “category labels” (“Performance  
Test of …”) and with test[1], I get the entries. Ie.:

```
    Plants
    100
    Customers
    50
    Total
    150

```

If I add another “each loop” into that existing loop, I don’t get  
what I’d expect. I tried:

```
    timing.each { |test|
      test[1].each { |test_values|
        puts test_values[0]
      }
    }

```

Now I’d expect to get Plants, Customers, Total, Work Lists, Bookmarks,  
Total. But I get:

```
    Plants
    100
    Plants
    85
    Plants
    111
    Work List
    17
    Work List
    10
    Work List
    22

```

So I only get the 1st “column” of the input data. Why’s that? And  
how would I do that correctly, as that’s obviously not the right  
way to go?

Thanks again,  
Michael

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 25, 2008, 3:37pm UTC](https://www.ruby-forum.com/t/changing-an-array-data-structure/127045/2 "2008-01-25T15:37:46Z")

</div>

2008/1/24, Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Hello.
> 
> I already asked about how I’d best re-order a datastructure. But  
> thinking about, I changed my mind; instead of the hash approach  
> I’ve shown in news:removed\_email\_address@domain.invalid,  
> I now think I might use arrays instead. Reason: The order in which  
> something is inserted and later fetched is important to me. With  
> Hashes in 1.8, this cannot easily be done out-of-the-box, can it?
> 
> Anyway - I’m now looking for a way to change the following arry:

This is not an Array but an object graph composed of nested Arrays.

> ```
> ]]
> 
> ```
> 
> ]
> 
> # This should become:
> 
> timing\_reordered = [  
> [“Performance Test of Item Access using Lists”, [  
> [“Plants”, [100, 85, 111]], [“Customers”, [50, 60, 77]], [“Total”, [150, 145, 188]]  
> ]],  
> [“Performance Test of Item Access using Advance Item Search”, [  
> [“Work List”, [17, 10, 22]], [“Bookmarks”, [30, 33, 27]], [“Total”, [42, 50, 99]]  
> ]]  
> ]

My first advice would be to use proper data types, e.g.

S1 = Struct.new :plants, :customers, :total  
S2 = Struct.new :work\_list, :bookmarks, :total

etc.

> It very much resembles the datastructure shown in the hash approach.  
> That’s only natural, if you take into consideration how the data is  
> generated. To do that, I’m running a method 3 (or more) times; these  
> methods generate the “Performance Test of Item Access using Lists”  
> and “Performance Test of Item Access using Advance Item Search” data.

For these you should use those structs (see above).

> These methods generate data; data items for Plants, Customers and  
> so on.
> 
> But for reporting, it’s best for me, if all the eg. Plants results  
> are “grouped together”. Actually, I only need the innermost arrays,  
> ie. [100, 85, 111], [50, 60, 77], … These arrays should be  
> concated, so that I’ve only got one long array, starting with: [100,  
> 85, 111, 50, 60, 77, …].

With the structs above

# data contains S1

data.inject(S1.new) do |s,d|  
(s.plants ||= []) \<\< d.plants  
(s.customers ||= []) \<\< d.customers  
(s.total ||= []) \<\< d.total  
s  
end

Alternatively

data.inject(:plants=\>[], :customers=\>[], :total=\>[]) do |s,d|  
d.members.each {|m| s[m.to\_sym] = d[m]}  
s  
end

Of course you need to take additional measures to cope with the  
nesting (S1 and S2).

Cheers

robert

---

<div class="post-metadata">

**Author:** ![wickie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/w/ba9def/32.png) [@wickie](https://www.ruby-forum.com/u/wickie)\
**Post date:** [January 25, 2008, 4:35pm UTC](https://www.ruby-forum.com/t/changing-an-array-data-structure/127045/3 "2008-01-25T16:35:33Z")

</div>

Robert K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > Anyway - I’m now looking for a way to change the following arry:  
> > [[“Work List”, 17], [“Bookmarks”, 30], [“Total”, 42]],  
> > [“Performance Test of Item Access using Advance Item Search”, [  
> > [“Work List”, [17, 10, 22]], [“Bookmarks”, [30, 33, 27]],  
> > [[“Total”, [42, 50, 99]]  
> > ]]  
> > ]
> 
> My first advice would be to use proper data types, e.g.
> 
> S1 = Struct.new :plants, :customers, :total  
> S2 = Struct.new :work\_list, :bookmarks, :total

Can I automatically create those elements of the Struct? I  
don’t want to have to fiddle with the data type, when a new  
test comes up. And I’d also like to have easy access to the  
name of the test in a well written way (ie. “Work List”).  
How do I iterate over the elements of the Struct? I absolutely  
do not want to have to rely on knowing the names of all these  
data points.

I think I’d be all set, if I could use hashes, because then  
I’d have all I need - but in Ruby 1.8, the order of the elements  
of a hash is not “stable”. Ie., I “insert” “Work List”, “Bookmarks”  
and “Total”, but when I iterate over the hash, I get back “Bookmarks”,  
“Work List” and “Total” ☹ No good ☹

As I don’t want to lose the order in which something has been  
added to the datastructure, I’m forced to use arrays in Ruby  
1.8, aren’t I?

[…]

> With the structs above
> 
> # data contains S1
> 
> data.inject(S1.new) do |s,d|  
> (s.plants ||= []) \<\< d.plants  
> (s.customers ||= []) \<\< d.customers  
> (s.total ||= []) \<\< d.total

Urgs. I don’t want to have to know that there’s a “plants”, “customers”,  
“total”, etc.pp…

Thanks a lot,

Michael
