Windows Vista Forums
Vista Forums Home Join Vista Forums Windows 7 Forum Vista Tutorials Tags
Welcome to Windows Vista Forums. Our forum is dedicated to helping you find solutions with any problems, errors or issues you are experiencing with Windows Vista. The Vista forum also covers news and updates and has an extensive Windows Vista tutorial section that covers a wide range of tips and tricks.

Go Back   Vista Forums > Misc Newsgroups > PowerShell

Vista - Copying an array and weird things about updating arrays...

Reply
 
Old 08-02-2008   #1 (permalink)
bruce1313


 
 

Copying an array and weird things about updating arrays...

Hi,
I'm new to powershell and in my messing around I've found that array
assignments behave pretty interestingly. It would be great if someone could
explain 1/ the right way to do this and 2/ exactly why I'm seeing what I do...

PS C:\Documents and Settings\Bruce> $c=1,2,3
PS C:\Documents and Settings\Bruce> $c
1
2
3
PS C:\Documents and Settings\Bruce> $d = $c
PS C:\Documents and Settings\Bruce> $d
1
2
3
PS C:\Documents and Settings\Bruce> $c[0]=99
PS C:\Documents and Settings\Bruce> $d
99 #<<< Hang on! I updated $c, not $d. is $d a reference to the same
object as $c?
2
3
PS C:\Documents and Settings\Bruce> $c+=100
PS C:\Documents and Settings\Bruce> $d #if $d is a reference then 100
should appear on the end of this too... nup.
99
2
3
PS C:\Documents and Settings\Bruce> $c
99
2
3
100
PS C:\Documents and Settings\Bruce>

Thanks in advance...
BB.

My System SpecsSystem Spec
Old 08-02-2008   #2 (permalink)
tojo2000


 
 

Re: Copying an array and weird things about updating arrays...

On Aug 2, 2:30*am, bruce1313 <bruce1...@xxxxxx>
wrote:
Quote:

> Hi,
> I'm new to powershell and in my messing around I've found that array
> assignments behave pretty interestingly. It would be great if someone could
> explain 1/ the right way to do this and 2/ exactly why I'm seeing what I do...
>
> PS C:\Documents and Settings\Bruce> $c=1,2,3
> PS C:\Documents and Settings\Bruce> $c
> 1
> 2
> 3
> PS C:\Documents and Settings\Bruce> $d = $c
> PS C:\Documents and Settings\Bruce> $d
> 1
> 2
> 3
> PS C:\Documents and Settings\Bruce> $c[0]=99
> PS C:\Documents and Settings\Bruce> $d * *
> 99 * #<<< Hang on! I updated $c, not $d. is $d a reference to the same
> object as $c?
> 2
> 3
> PS C:\Documents and Settings\Bruce> $c+=100
> PS C:\Documents and Settings\Bruce> $d * *#if $d is a reference then 100
> should appear on the end of this too... nup.
> 99
> 2
> 3
> PS C:\Documents and Settings\Bruce> $c
> 99
> 2
> 3
> 100
> PS C:\Documents and Settings\Bruce>
>
> Thanks in advance...
> BB.
Maybe someone can give a better answer, but as far as I can tell this
might be what is happening:

When you do this:

$d = $c

$c and $d are both names for the same object.

When you do $c += 100, this is essentially a shortcut for this:

$c = $c + 100

This evaluates $c, adds 100 to the end, and then assigns the name $c
to that result.

So it looks like when you increase the length of an array, a new array
object with the new length is created and assigned that name. It's
possible that there's some other explanation, but I'm pretty sure
that's what's going on.

If you don't want them to both point to the same object then you can
use the CopyTo() method of the array to copy the values, but it can be
kind of a pain because the destination array needs to be the same size
as the source, so alternatively you can do this:

$d = $($c)

That will evaluate $c and assign it to $d instead of assigning it to
the same object.
My System SpecsSystem Spec
Old 08-02-2008   #3 (permalink)
Alex K. Angelopoulos


 
 

Re: Copying an array and weird things about updating arrays...

Tojo is spot on, of course. I've inserted comments below - primarily on
using hashcodes to help see how the underlying object changes.

"tojo2000" <tojo2000@xxxxxx> wrote in message
news:dcb014ca-6239-44ba-9ff2-e4ef5525cfd1@xxxxxx
Quote:

> On Aug 2, 2:30 am, bruce1313 <bruce1...@xxxxxx>
> wrote:
Quote:
Quote:

>> PS C:\Documents and Settings\Bruce> $c=1,2,3
Quote:
Quote:

>> PS C:\Documents and Settings\Bruce> $d = $c
Quote:
Quote:

>> PS C:\Documents and Settings\Bruce> $c[0]=99
Quote:
Quote:

>> PS C:\Documents and Settings\Bruce> $d
>> 99 #<<< Hang on! I updated $c, not $d. is $d a reference to the same
>> object as $c?
>> 2
>> 3
>> PS C:\Documents and Settings\Bruce> $c+=100
Quote:
Quote:

>> PS C:\Documents and Settings\Bruce> $d #if $d is a reference then 100
>> should appear on the end of this too... nup.
>> 99
>> 2
>> 3
Quote:

> When you do this:
>
> $d = $c
>
> $c and $d are both names for the same object.
Exactly.
Quote:

> When you do $c += 100, this is essentially a shortcut for this:
>
> $c = $c + 100
>
> This evaluates $c, adds 100 to the end, and then assigns the name $c
> to that result.
>
> So it looks like when you increase the length of an array, a new array
> object with the new length is created and assigned that name. It's
> possible that there's some other explanation, but I'm pretty sure
> that's what's going on.
You reasoned it out correctly. It's possible to use the PSObject hashcodes
to help check identity, like this. Note that $e has a distinct hashcode from
$c and $d - it's just another object that happens to contain the same data.
When an element of $c is updated, the hashcodes for $c and $d stay the same.
As soon as the new element is added to $c, though, $c contains a new
object - which has a new hashcode.

PS> $c.GetHashCode()
7540993
PS> $d.GetHashCode()
7540993
PS> $e = 1,2,3
PS> $e.GetHashCode()
24062619
PS> $c[0] = 99
PS> $c.GetHashCode(),$d.GetHashCode()
7540993
7540993
PS> $c+=100
PS> $c.GetHashCode(),$d.GetHashCode()
66049492
7540993

Quote:

> If you don't want them to both point to the same object then you can
> use the CopyTo() method of the array to copy the values, but it can be
> kind of a pain because the destination array needs to be the same size
> as the source, so alternatively you can do this:
>
> $d = $($c)
>
> That will evaluate $c and assign it to $d instead of assigning it to
> the same object.


My System SpecsSystem Spec
Old 08-02-2008   #4 (permalink)
Kiron


 
 

Re: Copying an array and weird things about updating arrays...

PowerShell's array --arrayList and hashtable also-- assignment is done 'by reference'. Use the Clone Method to create a 'by value' copy of the same type array, hashTable or arrayList.
tojo2000's workaround is very practical for untyped arrays but be aware that it casts the copy of the a typed array and the copy of a arrayList into an object[].

# array assignment
$a1 = 1, 2, 3
$a2 = $a1 # <-- by reference
write-host $a1[0] $a2[0] -f 10 -b 0
$a1[0] = '!'
write-host $a1[0] $a2[0] -f 10 -b 0 # <-- $a2 is affected
$a3 = $a1.clone() # <-- by value
$a4 = $($a1) # <-- by value, only for array assignment
write-host $a1[0] $a2[0] $a3[0] $a4[0] -f 10 -b 0
$a1[0] = '?'
# $a2 is affected, while $a3 and $a4 aren't
write-host $a1[0] $a2[0] $a3[0] $a4[0] -f 10 -b 0
1..4 | % {iex "`$a$_.getType().fullName"}

# typed array assignment
[int[]]$ia1 = 1, 2, 3
$ia2 = $ia1 # <-- by reference
write-host $ia1[0] $ia2[0] -f 10 -b 0
$ia1[0] = 0
write-host $ia1[0] $ia2[0] -f 10 -b 0 # <-- $ia2 is affected
$ia3 = $ia1.clone() # <-- by value
$ia4 = $($ia1) # <-- by value, but not an [int[]]
write-host $ia1[0] $ia2[0] $ia3[0] $ia4[0] -f 10 -b 0
$ia1[0] = 9
# $ia2 is affected, while $ia3 and $ia4 aren't
write-host $ia1[0] $ia2[0] $ia3[0] $ia4[0] -f 10 -b 0
1..4 | % {iex "`$ia$_.getType().fullName"}

# hashtable assignment
$h1=@{} # empty hashtable
$h1.one = 1
$h1.two = 2
$h1.three = 3
$h2 = $h1 # <-- by reference
write-host $h1.one $h2.one -f 10 -b 0
$h1.one = '!'
write-host $h1.one $h2.one -f 10 -b 0 # <-- $h2 is affected
$h3 = $h1.clone() # <-- by value
$h4 = $($h1) # <-- by reference
write-host $h1.one $h2.one $h3.one $h4.one -f 10 -b 0
$h1.one = '?'
# $h2 and $h4 are affected, while $h3 isn't
write-host $h1.one $h2.one $h3.one $h4.one -f 10 -b 0
1..4 | % {iex "`$h$_.getType().fullName"}

# arrayList
$c1 = new-object System.Collections.ArrayList
[void]$c1.Add(1)
[void]$c1.Add(2)
[void]$c1.Add(3)
$c2 = $c1 # <-- by reference
write-host $c1[0] $c2[0]-f 10 -b 0
$c1[0] = 0
write-host $c1[0] $c2[0] -f 10 -b 0 # <-- $c2 is affected
$c3 = $c1.clone() # <-- by value
$c4 = $($c1) # by value as an array though
write-host $c1[0] $c2[0] $c3[0] $c4[0] -f 10 -b 0
$c1[0] = 9
# $c2 is affected; $c3 is not; $c4 elements not
# affected but $c4 is an array not an arrayList
write-host $c1[0] $c2[0] $c3[0] $c4[0] -f 10 -b 0
1..4 | % {iex "`$c$_.getType().fullName"}

--
Kiron
My System SpecsSystem Spec
Old 08-02-2008   #5 (permalink)
bruce1313


 
 

Re: Copying an array and weird things about updating arrays...

Thanks everyone, all the responses have added to my understanding.

So for a 2 dimensional array, I need to clone each of the 'rows'...

#not like this...
$x=(1,2),(3,4)
$y = $x.Clone()
$x.GetHashCode(),$y.GetHashCode() # <-- different
$x[0].gethashcode(),$y[0].gethashcode() # <-- the same...

#not by evaluating $x either - that gives the same result (except maybe data
types might be different)

#like this...
for($i=0;$i -lt $x.length;$i++) {
$z += ,($x[$i].clone())
}

$x[0].gethashcode(),$z[0].gethashcode()
63876281
33271828


My System SpecsSystem Spec
Old 08-03-2008   #6 (permalink)
tojo2000


 
 

Re: Copying an array and weird things about updating arrays...

On Aug 2, 4:29*pm, bruce1313 <bruce1...@xxxxxx>
wrote:
Quote:

> Thanks everyone, all the responses have added to my understanding.
>
> So for a 2 dimensional array, I need to clone each of the 'rows'...
>
> #not like this...
> *$x=(1,2),(3,4)
> *$y = $x.Clone()
> *$x.GetHashCode(),$y.GetHashCode() * # <-- different
> *$x[0].gethashcode(),$y[0].gethashcode() * # <-- the same...
>
> #not by evaluating $x either - that gives the same result (except maybe data
> types might be different)
>
> #like this...
> for($i=0;$i -lt $x.length;$i++) {
> * *$z += ,($x[$i].clone())
>
> }
>
> $x[0].gethashcode(),$z[0].gethashcode()
> 63876281
> 33271828
I have to say, I'm glad you ran into this before I did, because it's a
doozy.

Here's a workaround that should work for you. It works for arrays
only.

function New-Hashcode($var) {
if ($var.GetType().Name -eq 'Object[]) {
$var += 0
$var = $var[0..($var.Length - 2)]

foreach($index in (0..($var.Length -1))) {
$var[$index] = New-Hashcode $var[$index]
}
}

return $var
}

PS C:\> $y = New-Hashcode($x)
PS C:\> $x.GetHashCode()
5696624
PS C:\> $y.GetHashCode()
27443610
PS C:\> $x[0].GetHashCode()
41883196
PS C:\> $y[0].GetHashCode()
35846188


Oddly enough it doesn't work for strings, but here's another
workaround for strings:

$newstring = $string.Split('')
My System SpecsSystem Spec
Old 08-03-2008   #7 (permalink)
Kiron


 
 

Re: Copying an array and weird things about updating arrays...

You got it Bruce. But what you're copying is a nested array, not a multi-dimensional array.
To copy a multi-dimensional array 'by value' use the Clone Method.
To copy a one level nested _array of arrays_ --or nested arrays-- 'by value' and keep the arrays' type, clone the innermost arrays.
You can use the pipeline to simplify the process and avoid the For Loop.
For a one level nested array is pretty simple, but it gets trickier as the nested level increases.

# multi-dimensional arrays
# 3D string array
$x = new-object 'string[,,]' 2,2,2
$x[0,0,0] = 'number 1'
$x[0,0,1] = 'number 2'
$x[0,1,0] = 'number 3'
$x[0,1,1] = 'number 4'
$x[1,0,0] = 'number 5'
$x[1,0,1] = 'number 6'
$x[1,1,0] = 'number 7'
$x[1,1,1] = 'number 8'
$y = $x.clone()
write-host Before $x[0,0,0] $y[0,0,0] -f 11 -b 0
$x[0,0,0] = 'number 13'
write-host After $x[0,0,0] $y[0,0,0] -f 10 -b 0
# array type is maintained
write-host $x.getType().name $y.getType().name
# different objects
write-host $x.getHashCode() $y.getHashCode()

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

# array of arrays, or nested arrays
rv x,y -ea 0
$x = [byte[]](1,2),[uInt16[]](3,4)
$y = $x | % {,$_.clone()}
write-host Before $x[0][0] $y[0][0] -f 11 -b 0
$x[0][0] = 13
write-host After $x[0][0] $y[0][0] -f 10 -b 0
# array types are maintained
0..1 | % {write-host $x[$_].getType().name $y[$_].getType().name}
# different objects
0..1 | % {write-host $x[$_].getHashCode() $y[$_].getHashCode()}

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

rv x, y -ea 0
$x = ([int[]](1,2),[long[]](3,4)),([decimal[]](5,6),[double[]](7,8))
$y = $x | % {$x1 = $_ | % {,$_.clone()}; ,$x1; rv x1}
write-host Before $x[0][0][0] $y[0][0][0] -f 11 -b 0
$x[0][0][0] = 13
write-host After $x[0][0][0] $y[0][0][0] -f 10 -b 0
# array types are maintained
0..1 | % {$i = $_; 0..1 | % {
write-host $x[$i][$_].getType().name $y[$i][$_].getType().name
}
}
# different objects
0..1 | % {$i = $_; 0..1 | % {
write-host $x[$i][$_].getHashCode() $y[$i][$_].getHashCode()
}
}

--
Kiron
My System SpecsSystem Spec
Old 08-03-2008   #8 (permalink)
tojo2000


 
 

Re: Copying an array and weird things about updating arrays...

On Aug 3, 2:01*am, tojo2000 <tojo2...@xxxxxx> wrote:
Quote:

> On Aug 2, 4:29*pm, bruce1313 <bruce1...@xxxxxx>
> wrote:
>
>
>
Quote:

> > Thanks everyone, all the responses have added to my understanding.
>
Quote:

> > So for a 2 dimensional array, I need to clone each of the 'rows'...
>
Quote:

> > #not like this...
> > *$x=(1,2),(3,4)
> > *$y = $x.Clone()
> > *$x.GetHashCode(),$y.GetHashCode() * # <-- different
> > *$x[0].gethashcode(),$y[0].gethashcode() * # <-- the same...
>
Quote:

> > #not by evaluating $x either - that gives the same result (except maybedata
> > types might be different)
>
Quote:

> > #like this...
> > for($i=0;$i -lt $x.length;$i++) {
> > * *$z += ,($x[$i].clone())
>
Quote:

> > }
>
Quote:

> > $x[0].gethashcode(),$z[0].gethashcode()
> > 63876281
> > 33271828
>
> I have to say, I'm glad you ran into this before I did, because it's a
> doozy.
>
> Here's a workaround that should work for you. *It works for arrays
> only.
>
> function New-Hashcode($var) {
> * if ($var.GetType().Name -eq 'Object[]) {
> * * $var += 0
> * * $var = $var[0..($var.Length - 2)]
>
> * * foreach($index in (0..($var.Length -1))) {
> * * * $var[$index] = New-Hashcode $var[$index]
> * * }
> * }
>
> * return $var
>
> }
>
> PS C:\> $y = New-Hashcode($x)
> PS C:\> $x.GetHashCode()
> 5696624
> PS C:\> $y.GetHashCode()
> 27443610
> PS C:\> $x[0].GetHashCode()
> 41883196
> PS C:\> $y[0].GetHashCode()
> 35846188
>
> Oddly enough it doesn't work for strings, but here's another
> workaround for strings:
>
> $newstring = $string.Split('')
BTW, if anyone knows, what exactly is the hashcode? Is it really
there to be used as the identity, or is it just so unique that it can
be used for that. I tried looking it up on MSDN but all I found out
is that GetHashCode() is overridden for PSObject.
My System SpecsSystem Spec
Reply

Thread Tools


Similar Threads
Thread Forum
associative array of associative arrays PowerShell
Weird things in User folder. Vista file management
copying files referenced in an array...help? PowerShell
Newbie question - Copying files listed in an array PowerShell
Hashtable with array as a key .... weird behaviour PowerShell


Vista Forums is an independent web site and has not been authorized,
sponsored, or otherwise approved by Microsoft Corporation.
"Windows Vista", the Start Orb, and related materials are trademarks of Microsoft Corp.
© Designer Media Ltd

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46