weird behavior pushing an array onto an array

E

eagle eyes joe

Greetings,

In my program, I fill an array, a, with data and push it onto an array b
which is initially empty. At each iteration, all the previous pushed
values become the same as the last item, so I end up with an array of
many copies of the last item.

Can you please help?


Joe.






(rdb:1) c
ACFFX 25.01 15.13 3.25 0 1.45 0
Breakpoint 1, toplevel at funds:65
funds:66: a.fill(0)
(rdb:1) p a
["ACFFX", "25.01", "15.13", "3.25", 0, "1.45", 0]
(rdb:1) p b
[["ACFFX", "25.01", "15.13", "3.25", 0, "1.45", 0], ["ACFFX", "25.01",
"15.13", "3.25", 0, "1.45", 0], ["ACFFX", "25.01", "15.13", "3.25", 0,
"1.45", 0], ["ACFFX", "25.01", "15.13", "3.25", 0, "1.45", 0]]
(rdb:1) c
ACINX 28.53 15.63 3.95 7.76 1.05 0
Breakpoint 1, toplevel at funds:65
funds:65: b.push(a)
(rdb:1) p a
["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0]
(rdb:1) p b
[["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0], ["ACINX",
"28.53", "15.63", "3.95", "7.76", "1.05", 0], ["ACINX", "28.53",
"15.63", "3.95", "7.76", "1.05", 0], ["ACINX", "28.53", "15.63", "3.95",
"7.76", "1.05", 0]]
(rdb:1) exit
[Abba:~/ruby] josephal% cat funds
#!/usr/bin/ruby

....

a = Array.new(7, 0) # a is the line item
b = Array.new # b is the array of arrays
....

r.each do |i|
...
b.push(a)
...
end
 
F

Florian Gross

eagle said:
Greetings,
Moin.

In my program, I fill an array, a, with data and push it onto an array b
which is initially empty.

You push the same array over and over. You want to push a copy instead.
Use #clone or #dup to get a copy of the Array.

Regards,
Florian Gross
 
B

Brian Candler

In my program, I fill an array, a, with data and push it onto an array b
You push the same array over and over. You want to push a copy instead.
Use #clone or #dup to get a copy of the Array.

Beware that may not be enough by itself, because the array contains strings;
even if you dup the array you will still have references to the same
strings. This will become apparent if you later modify one of the strings:

a = ["one","two","three"]
b = []
b << a.dup << a.dup
b[0][0] << "XXX"
p b
# => [["oneXXX", "two", "three"], ["oneXXX", "two", "three"]]

But it's not an issue if you only ever replace the array elements with a
reference to another object, e.g.

b[0][0] = "newstring"

A safer way is to fill the array directly:

b = []
5.times do
b << ["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0]
end

Or more compactly,

b = (1..5).collect { ["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0] }

That's because each time a constant like "ACINX" is executed, it creates a
brand new String object; equally, each time [ ... ] is executed it creates a
brand new Array object.

Alternatively, you can do a "deep copy" of the array and its contents. A
quick and fairly convenient way to do this is with Marshal, to serialise the
object and then create a fresh object tree from the serialised form.

a = ["one","two","three"]
b = []
b << Marshal.load(Marshal.dump(a)) << Marshal.load(Marshal.dump(a))
b[0][0] << "XXX"
p b
# => [["oneXXX", "two", "three"], ["one", "two", "three"]]

Regards,

Brian.
 
F

Florian Gross

Brian said:
Beware that may not be enough by itself, because the array contains strings;
even if you dup the array you will still have references to the same
strings. This will become apparent if you later modify one of the strings:

Thank you for the correction, you are right of course.
Or more compactly,

b = (1..5).collect { ["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0] }

Or even this:

b = Array.new(5) { ["ACINX", "28.53", "15.63", "3.95", "7.76", "1.05", 0] }
Regards,
Brian.

More regards,
Florian Gross
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top