Array funkiness?

K

Kyle Schmitt

When trying to append to an array that lives in an array, it appends
to all until the individual array is used with =

Here's exactly what I did

irb(main):007:0> a=Array.new(9,Array.new())
I expect and I get [[], [], [], [], [], [], [], [], []]

irb(main):008:0> a[0]<<1
I expect [[1], [], [], [], [], [], [], [], []]
but I get [[1], [1], [1], [1], [1], [1], [1], [1], [1]]

irb(main):009:0> a[0]<<1
I expect [[1,1], [], [], [], [], [], [], [], []]
but I get [[1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1,
1], [1, 1]]

irb(main):010:0> a[0]=[1,2,3]
I expect [[1,2,3], [], [], [], [], [], [], [], []]
but I get [[1,2,3], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1],
[1, 1], [1, 1]]

So once more
irb(main):011:0> a[0]<<1
originally I would have expected
I expect [[1,2,3,1], [], [], [], [], [], [], [], []]
now because of this wacky behavior I expect
[[1, 2, 3, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1],
[1, 1,1], [1, 1, 1], [1, 1, 1]]
but what actually happens? This
[[1, 2, 3, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1]]

What on earth is happening?

--Kyle

PS: I do have a work around so my code works as I expected it, using
+= instead of <<i, but I really want to know _why_ here.
 
P

Phrogz

When trying to append to an array that lives in an array, it appends
to all until the individual array is used with =

Here's exactly what I did

irb(main):007:0> a=Array.new(9,Array.new())
I expect and I get [[], [], [], [], [], [], [], [], []]

irb(main):008:0> a[0]<<1
I expect [[1], [], [], [], [], [], [], [], []]
but I get [[1], [1], [1], [1], [1], [1], [1], [1], [1]]

The short answer is "RTFM" - type in
ri Array.new
in your console and you'll see all this described.

The nice longer answer follows.

You basically asked Ruby to do:
b = Array.new
a = [b,b,b,b,b,b,b,b,b]
so modifying any particular instance modifies them all.

What you wanted was:
irb(main):001:0> a = Array.new(9){ Array.new }
=> [[], [], [], [], [], [], [], [], []]
irb(main):002:0> a[0] << 1
=> [1]
irb(main):003:0> a
=> [[1], [], [], [], [], [], [], [], []]
 
S

Sebastian Hungerecker

Kyle said:
When trying to append to an array that lives in an array, it appends
to all until the individual array is used with =

Here's exactly what I did

irb(main):007:0> a=Array.new(9,Array.new())
I expect and I get [[], [], [], [], [], [], [], [], []]

You probably also expect those nine arrows to be nine different empty arrays
(the result of calling Array.new nine times), but that is not the case.
Array.new is called exactly once and a[0] to a[8] point to the empty array
resulting from that.
So naturally if you change one of the arrays, you change them all, because
they're all the same array.
If you however replace one of the arrays with another array, the rest aren't
affected.
I hope I explained this right and helped you understand.
 
K

Kyle Schmitt

Ahh. Any clue as to what the rational on making Array.new work that was was?
I can think of situations where I'd want to use the same object over
and over, but more situations where I'd want a new object in each one.

Thanks alot!
--Kyle
 
A

Austin Ziegler

Ahh. Any clue as to what the rational on making Array.new work that was was?
I can think of situations where I'd want to use the same object over
and over, but more situations where I'd want a new object in each one.

Yes.

bitvector = Array.new(32, 0)

If you need complex handling, as others have pointed out, use the block form.

-austin
 
J

Just Another Victim of the Ambient Morality

Kyle Schmitt said:
Ahh. Any clue as to what the rational on making Array.new work that was
was?
I can think of situations where I'd want to use the same object over
and over, but more situations where I'd want a new object in each one.

Yes, because the other way isn't really possible. Think about it.
You're asking the array class to take the second parameter and... do what
with it, exactly? Call the .dup method on it? That requires you to
needlessly assume the object has defined that method, an assumption we'd
rather not make if we didn't have to...
The way it is now, it's very natural to use the second parameter to
reference that object multiple times. Furthermore, the block naturally
performs whatever code that block does for each element, like iterators.
Thus, duplication is natural...
If you read the manual, you'll see that this really is the better
interface...
 
M

Martin DeMello

You basically asked Ruby to do:
b = Array.new
a = [b,b,b,b,b,b,b,b,b]
so modifying any particular instance modifies them all.

And the reason a[0] += works is that internally it gets converted
to a[0] = a[0] + i, so that it returns a different object altogether.

martin
 

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

Forum statistics

Threads
474,234
Messages
2,571,178
Members
47,809
Latest member
Adisty

Latest Threads

Top