[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Array changing after concat function

WKC CCC

12/7/2006 5:08:00 PM

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

--
Posted via http://www.ruby-....

16 Answers

matt

12/7/2006 5:17:00 PM

0

WKC CCC <wai-kee.chung@uk.bnpparibas.com> wrote:

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

--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

WKC CCC

12/7/2006 5:38:00 PM

0

unknown wrote:
> WKC CCC <wai-kee.chung@uk.bnpparibas.com> 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?

Thanks,

--
Posted via http://www.ruby-....

WKC CCC

12/7/2006 5:52:00 PM

0

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?


--
Posted via http://www.ruby-....

Stefano Crocco

12/7/2006 5:57:00 PM

0

Alle 18:37, giovedì 7 dicembre 2006, WKC CCC ha scritto:
> unknown wrote:
> > WKC CCC <wai-kee.chung@uk.bnpparibas.com> 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?
>
> Thanks,

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

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
change the array. The objects it contains don't change.
* when you call an element's method (such as, in your example, concat), you
don't change the array. Other variables referring to the same object, share
that change.

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

Stefano

Paul Lutus

12/7/2006 6:33:00 PM

0

WKC CCC wrote:

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

But the "clone" method is included in the API documentation, it is a
question of locating which class it belongs to. Remember that members of a
particular class inherit the methods of that class's ancestors as well as
its own.

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

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

--
Paul Lutus
http://www.ara...

dblack

12/7/2006 6:38:00 PM

0

Paul Lutus

12/7/2006 7:56:00 PM

0

dblack@wobblini.net wrote:

> Hi --
>
> On Fri, 8 Dec 2006, Paul Lutus wrote:
>
>> 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.

Thanks! I was in irb when I applied this non-"fix".

--
Paul Lutus
http://www.ara...

matt

12/7/2006 8:30:00 PM

0

WKC CCC <wai-kee.chung@uk.bnpparibas.com> wrote:

> unknown wrote:
> > WKC CCC <wai-kee.chung@uk.bnpparibas.com> 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.

--
matt neuburg, phd = matt@tidbits.com, http://www.tidbits...
Tiger - http://www.takecontrolbooks.com/tiger-custom...
AppleScript - http://www.amazon.com/gp/product/...
Read TidBITS! It's free and smart. http://www.t...

Drew Olson

12/7/2006 8:50:00 PM

0

WKC CCC wrote:
> 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]

--
Posted via http://www.ruby-....

Stefano Crocco

12/7/2006 9:02:00 PM

0

Alle 21:49, giovedì 7 dicembre 2006, Drew Olson ha scritto:
> WKC CCC wrote:
> > 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]

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

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

What clone (and dup) produce are shallow copies, that is the object is copied,
but their contents are not: a contains exactly the same objects than b does.
Because of this, you can't change one of the elements of b whitout changing
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: you
can add an element to a whithout changing b. But here you're changing the
arrays, not he objects they contain, which was the problem of the original
poster.

Stefano