[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Changing an array data structure

Michael Schmarck

1/24/2008 3:01:00 PM

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:6233013.YDsyxgeUJ1@michael-schmarck.my-fqdn.de>,
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
2 Answers

Robert Klemme

1/25/2008 2:37:00 PM

0

2008/1/24, Michael Schmarck <michael.schmarck@here.la>:
> 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:6233013.YDsyxgeUJ1@michael-schmarck.my-fqdn.de>,
> 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.

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

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

--
use.inject do |as, often| as.you_can - without end

Michael Schmarck

1/25/2008 3:31:00 PM

0

Robert Klemme <shortcutter@googlemail.com> wrote:

> 2008/1/24, Michael Schmarck <michael.schmarck@here.la>:
>> 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:6233013.YDsyxgeUJ1@michael-schmarck.my-fqdn.de>,
>> 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.
>
>> 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]]
>> ]]
>> ]
>
> 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