Array changing after concat function

W

WKC CCC

Can someone shed some light on this problem. In the example, I am
attempting to concatenate two arrays together. However it appears that
the contents of the first array is being altered after using the concat
function even though a copy of the array is being used. Am I doing
something wrong here, or is this a potential bug?

Thanks

one = [[1],[2]]
two = [['a'],['b']]

puts one.inspect

newArray =[]
count = 0

tempArr = Array.new(one)

tempArr.each do |x|
x = x.concat(two.values_at(count))
newArray = newArray.push(x)
count = count + 1
end

puts one.inspect
 
M

matt neuburg

WKC CCC said:
Can someone shed some light on this problem. In the example, I am
attempting to concatenate two arrays together. However it appears that
the contents of the first array is being altered after using the concat
function even though a copy of the array is being used. Am I doing
something wrong here, or is this a potential bug?

Thanks

one = [[1],[2]]
two = [['a'],['b']]

puts one.inspect

newArray =[]
count = 0

tempArr = Array.new(one)

tempArr.each do |x|
x = x.concat(two.values_at(count))
newArray = newArray.push(x)
count = count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.
 
W

WKC CCC

unknown said:
WKC CCC said:
count = count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.

If they are referring to the same object, why is it when

tempArr = Array.new(one)
one.clear

results in tempArr still having the values originally assigned to array
one?

Thanks,
 
W

WKC CCC

I've found that using:

copy = one.map { |el| el.clone }

will copy all elements into the new array without referring to the same
object.
Is there a reason why the clone function has been ommitted from the API
doc?
 
S

Stefano Crocco

Alle 18:37, gioved=C3=AC 7 dicembre 2006, WKC CCC ha scritto:
unknown said:
WKC CCC said:
count =3D count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.

If they are referring to the same object, why is it when

tempArr =3D Array.new(one)
one.clear

results in tempArr still having the values originally assigned to array
one?

Thanks,

tempArray and one are two different objects (as you can see using object_id=
),=20
but the objects they contain are the same (again, use object_id to check=20
this: one[0].object_id and tempArray[0].object_id return the same value).=20
When you call one.clear, you are changing the array itself, not the objects=
=20
it contains. Instead, when in your block you call x.concat (where x is one =
of=20
the elements of tempArray), you aren't changing the tempArray, but its=20
elements.=20

The array and the objects it contains don't speak to each other, so:
* when you call an array's method (array.clear, array.reverse!,...), you=20
change the array. The objects it contains don't change.
* when you call an element's method (such as, in your example, concat), you=
=20
don't change the array. Other variables referring to the same object, share=
=20
that change.

I fear my explanation makes this topic look more confusing than it actually=
=20
is, but I hope it's useful.

Stefano
 
D

dblack

Hi --

For a given object, to display a sorted list of the methods available to it,
do this:

puts (object).methods.sort.join("\n")

You don't need to do the join("\n") -- puts will puts each item in
turn.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

matt neuburg

WKC CCC said:
unknown said:
WKC CCC said:
count = count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.

If they are referring to the same object, why is it when

tempArr = Array.new(one)
one.clear

results in tempArr still having the values originally assigned to array
one?

Reread what I said. I didn't say that tempArr and one refer to the same
object; I said that tempArr[0] and one[0] (and so on) refer to the same
object.

Think of it this way. Items in an array are dogs. Arrays are people
holding leashes. Anyone can attach a leash to a dog. So I (tempArr) can
have a leash on Fido, and so can you (one). If you let go of your leash
(one.clear), Fido is still Fido; you just don't have a leash on him. But
if you cut off one Fido's legs (modify one[0]), that leg on my Fido
(tempArr[0]) is also cut off, because they are the same Fido.

m.
 
D

Drew Olson

WKC said:
I've found that using:

copy = one.map { |el| el.clone }

will copy all elements into the new array without referring to the same
object.
Is there a reason why the clone function has been ommitted from the API
doc?

It seems much simpler to just clone the array rather than each element
individually:

irb(main):001:0> a=[]
=> []
irb(main):002:0> 10.times{|i| a << i}
=> 10
irb(main):003:0> a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):004:0> b = a.clone
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):005:0> a[0] = 10
=> 10
irb(main):006:0> a
=> [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):007:0> b
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 
S

Stefano Crocco

Alle 21:49, gioved=C3=AC 7 dicembre 2006, Drew Olson ha scritto:
WKC said:
I've found that using:

copy =3D one.map { |el| el.clone }

will copy all elements into the new array without referring to the same
object.
Is there a reason why the clone function has been ommitted from the API
doc?

It seems much simpler to just clone the array rather than each element
individually:

irb(main):001:0> a=3D[]
=3D> []
irb(main):002:0> 10.times{|i| a << i}
=3D> 10
irb(main):003:0> a
=3D> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):004:0> b =3D a.clone
=3D> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):005:0> a[0] =3D 10
=3D> 10
irb(main):006:0> a
=3D> [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):007:0> b
=3D> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Your code doesn't solve the problem. If a contains mutable objects, such as=
=20
arrays, what happens is this:

irb(main):001:0> a=3D[[1,2],[3,4]]
=3D> [[1, 2], [3, 4]]
irb(main):002:0> b=3Da.clone
=3D> [[1, 2], [3, 4]]
irb(main):003:0> b[0].push 5
=3D> [1, 2, 5]
irb(main):004:0> a
=3D> [[1, 2, 5], [3, 4]]
irb(main):005:0>

What clone (and dup) produce are shallow copies, that is the object is copi=
ed,=20
but their contents are not: a contains exactly the same objects than b does=
=2E=20
Because of this, you can't change one of the elements of b whitout changing=
=20
the element of a: the two are the same object.

Instead, what your example shows is that a and b are not the same object: y=
ou=20
can add an element to a whithout changing b. But here you're changing the=20
arrays, not he objects they contain, which was the problem of the original=
=20
poster.

Stefano
 
D

dblack

Hi --

WKC said:
I've found that using:

copy = one.map { |el| el.clone }

will copy all elements into the new array without referring to the same
object.
Is there a reason why the clone function has been ommitted from the API
doc?

It seems much simpler to just clone the array rather than each element
individually:

irb(main):001:0> a=[]
=> []
irb(main):002:0> 10.times{|i| a << i}
=> 10
irb(main):003:0> a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):004:0> b = a.clone
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):005:0> a[0] = 10
=> 10
irb(main):006:0> a
=> [10, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):007:0> b
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

But that won't do a deep cloning, which is what it sounds like WKC
wants:

irb(main):001:0> a = [""]
=> [""]
irb(main):002:0> a[0].object_id
=> -604580558
irb(main):003:0> a.clone[0].object_id
=> -604580558
irb(main):004:0> a.map {|e| e.clone }[0].object_id
=> -604623258


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
L

Logan Capaldo

WKC CCC said:
unknown said:
count = count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.

If they are referring to the same object, why is it when

tempArr = Array.new(one)
one.clear

results in tempArr still having the values originally assigned to array
one?

Reread what I said. I didn't say that tempArr and one refer to the same
object; I said that tempArr[0] and one[0] (and so on) refer to the same
object.

Think of it this way. Items in an array are dogs. Arrays are people
holding leashes. Anyone can attach a leash to a dog. So I (tempArr) can
have a leash on Fido, and so can you (one). If you let go of your leash
(one.clear), Fido is still Fido; you just don't have a leash on him. But
if you cut off one Fido's legs (modify one[0]), that leg on my Fido
(tempArr[0]) is also cut off, because they are the same Fido.

m.
That is the most disturbed, and yet apt analogy ever. Mind if I quote you?
 
M

matt neuburg

Logan Capaldo said:
WKC CCC said:
unknown wrote:


count = count + 1
end

puts one.inspect

Array.new(array) copies the *array* but it does not copy its *elements*.
So tempArr[0] is another name for the very same object as one[0], and so
forth. m.

If they are referring to the same object, why is it when

tempArr = Array.new(one)
one.clear

results in tempArr still having the values originally assigned to array
one?

Reread what I said. I didn't say that tempArr and one refer to the same
object; I said that tempArr[0] and one[0] (and so on) refer to the same
object.

Think of it this way. Items in an array are dogs. Arrays are people
holding leashes. Anyone can attach a leash to a dog. So I (tempArr) can
have a leash on Fido, and so can you (one). If you let go of your leash
(one.clear), Fido is still Fido; you just don't have a leash on him. But
if you cut off one Fido's legs (modify one[0]), that leg on my Fido
(tempArr[0]) is also cut off, because they are the same Fido.

m.
That is the most disturbed, and yet apt analogy ever

Clearly you've never read any of my books.
Mind if I quote you?

Woof! (That means "Be my guest.") m.
 
E

Edwin Fine

unknown said:
Logan Capaldo said:
puts one.inspect
results in tempArr still having the values originally assigned to array
if you cut off one Fido's legs (modify one[0]), that leg on my Fido
(tempArr[0]) is also cut off, because they are the same Fido.

m.
That is the most disturbed, and yet apt analogy ever

Clearly you've never read any of my books.
Mind if I quote you?

Woof! (That means "Be my guest.") m.

(Off-topic to Matt)
The best languages are dead languages? Did I translate that correctly?
 
M

matt neuburg

Edwin Fine said:
unknown said:
Logan Capaldo said:
puts one.inspect
results in tempArr still having the values originally assigned to array
if you cut off one Fido's legs (modify one[0]), that leg on my Fido
(tempArr[0]) is also cut off, because they are the same Fido.

m.

That is the most disturbed, and yet apt analogy ever

Clearly you've never read any of my books.
Mind if I quote you?

Woof! (That means "Be my guest.") m.

(Off-topic to Matt)
The best languages are dead languages? Did I translate that correctly?

Close enough. :) m.
 

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,774
Messages
2,569,596
Members
45,139
Latest member
JamaalCald
Top