0

Arrays by reference

Working fine!

The normal way to pass an Array by-reference in PowerShell seems to work fine:

Function Swap-Array ($theArray, $theArrayB, [int]$indexToSwap) {
  $temp = $theArrayA[$indexToSwap];
  $theArrayA[$indexToSwap] = $theArrayB[$indexToSwap];
  $theArrayB[$indexToSwap] = $temp;
} 

$a = @(1,2,3,4)
$b = @(3,2,4,1)
$a
$b
Swap-Array $a, $b, 2
$a
$b

Output:

a
-
1
2
3
4

b
-
3
2
4
1

a
-
1
2
4
3

b
-
3
2
3
1

The problem

Adding Objects

The issue arises when the array by-refernece is a container of PSObjects that's not static, and I am attempting to add a new record. Modifying the existing records seems to be fine!

Function Swap-Apples($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Apples;
  $objectA[$indexToSwap].Apples = $objectB[$indexToSwap].Apples;
  $objectB[$indexToSwap].Apples = $temp;
}

Function Swap-Oranges($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Oranges;
  $objectA[$indexToSwap].Oranges = $objectB[$indexToSwap].Oranges;
  $objectB[$indexToSwap].Oranges = $temp;
}

<# heres the problematic bit #>
Function Add-Fruit ($object, [int]$howManyApples, [int]$howManyOranges) {
  $hAdd = @{
    Apples=$howManyApples
    Oranges=$howManyOranges
  }
  $hToAdd = New-Object -TypeName PSObject -Property $hAdd;
  $object += $hToAdd;
}

$a = @();
$b = @();
$a1 = @{
  Apples=3
  Oranges=2
}
$b1 = @{
  Apples=5
  Oranges=7
}
$a2 = @{
  Apples=6
  Oranges=3
}
$b2 = @{
  Apples=1
  Oranges=5
}
$aObject1 = New-Object -TypeName PSObject -Property $a1;
$bObject1 = New-Object -TypeName PSObject -Property $b1;
$aObject2 = New-Object -TypeName PSObject -Property $a2;
$bObject2 = New-Object -TypeName PSObject -Property $b2;
$a += $aObject1; $a += $aObject2;
$b += $bObject1; $b += $aObject2;

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Now lets make a trade`!";
Swap-Apples $a $b 0
Swap-Oranges $a $b 1

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Hey, I brought more fruit for A`!";
Add-Fruit -object $a -howManyApples 5 -howManyOranges 2

Write-Host "Values of A";
$a | Format-List

Write-Host "I brought more fruit for B too`!";
Add-Fruit -object $b -howManyApples 5 -howManyOranges 3

Write-Host "Values of B";
$b | Format-List

Output

Values of A


Oranges : 2
Apples  : 3

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 5

Oranges : 3
Apples  : 6



Now lets make a trade!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6



Hey, I brought more fruit for A!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6



I brought more fruit for B too!
Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6

The Swap-Apples and Swap-Oranges Functions seem to work fine. The program falls apart at the last segment, trying to give both A and B more fruit ! This would otherwise normally work in Local Scope. I feel like this is falling apart due to by-reference passing.

How would I go about fixing the problem at the end of this program ?

Robert Smith
  • 309
  • 3
  • 10

2 Answers2

0

The Solution

Dynamic ArrayLists

In PowerShell, you can create arrays of both fixed-size and dynamically allocated. If I would like to give both A and B more objects, I have to tell PowerShell that this is an ArrayList and not the typical standard Array.

This means I cannot declare my array like this:

$a = @();
$b = @();

This type in .NET is called System.Collections.ArrayList and can be passed by-reference in a PowerShell program, like so:

$a = New-Object -TypeName 'System.Collections.ArrayList';
$b = New-Object -TypeName 'System.Collections.ArrayList';

Now its not fixed-size, so I can add records anywhere in my program at my leasure, even by reference!

Here is the solution:

Function Swap-Apples($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Apples;
  $objectA[$indexToSwap].Apples = $objectB[$indexToSwap].Apples;
  $objectB[$indexToSwap].Apples = $temp;
}

Function Swap-Oranges($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Oranges;
  $objectA[$indexToSwap].Oranges = $objectB[$indexToSwap].Oranges;
  $objectB[$indexToSwap].Oranges = $temp;
}

<# ArrayList! #>
Function Add-Fruit ([System.Collections.ArrayList]$object, [int]$howManyApples, [int]$howManyOranges) {
  $hAdd = @{
    Apples=$howManyApples
    Oranges=$howManyOranges
  }
  $hToAdd = New-Object -TypeName PSObject -Property $hAdd;
  <# We have to call the ArrayList Add method to add to our dynamic object #>
  $object.Add($hToAdd);
}

$a = New-Object -TypeName 'System.Collections.ArrayList';
$b = New-Object -TypeName 'System.Collections.ArrayList';
$a1 = @{
  Apples=3
  Oranges=2
}
$b1 = @{
  Apples=5
  Oranges=7
}
$a2 = @{
  Apples=6
  Oranges=3
}
$b2 = @{
  Apples=1
  Oranges=5
}
$aObject1 = New-Object -TypeName PSObject -Property $a1;
$bObject1 = New-Object -TypeName PSObject -Property $b1;
$aObject2 = New-Object -TypeName PSObject -Property $a2;
$bObject2 = New-Object -TypeName PSObject -Property $b2;
<# Here we call the ArrayList Add method #>
$a.Add($aObject1); $a.Add($aObject2);
$b.Add($bObject1); $b.Add($aObject2);

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Now lets make a trade`!";
Swap-Apples $a $b 0
Swap-Oranges $a $b 1

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Hey, I brought more fruit for A`!";
Add-Fruit -object $a -howManyApples 5 -howManyOranges 2

Write-Host "Values of A";
$a | Format-List

Write-Host "I brought more fruit for B too`!";
Add-Fruit -object $b -howManyApples 5 -howManyOranges 3

Write-Host "Values of B";
$b | Format-List

And the (somewhat) intended output (see below):

0
1
0
1
Values of A


Oranges : 2
Apples  : 3

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 5

Oranges : 3
Apples  : 6



Now lets make a trade!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6



Hey, I brought more fruit for A!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6

Oranges : 2
Apples  : 5



I brought more fruit for B too!
Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6

Oranges : 3
Apples  : 5

Extra output ?

If you observed in the output:

0
1
0
1

The Add Method of ArrayList returns the index of the record you Added. Since it returns this value it drops out of your pipe into Std-Out, so make sure you direct it accordingly.

If you don't need this output in your program like I don't here, pipe it to the null device, like so:

$a.Add($aObject1) | Out-Null; $a.Add($aObject2) | Out-Null;
$b.Add($bObject1) | Out-Null; $b.Add($aObject2) | Out-Null;

And here's the final program/output:

Code: (Arraytest.ps1)

Function Swap-Apples($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Apples;
  $objectA[$indexToSwap].Apples = $objectB[$indexToSwap].Apples;
  $objectB[$indexToSwap].Apples = $temp;
}

Function Swap-Oranges($objectA, $objectB, $indexToSwap) {
  $temp = $objectA[$indexToSwap].Oranges;
  $objectA[$indexToSwap].Oranges = $objectB[$indexToSwap].Oranges;
  $objectB[$indexToSwap].Oranges = $temp;
}

<# ArrayList! #>
Function Add-Fruit ([System.Collections.ArrayList]$object, [int]$howManyApples, [int]$howManyOranges) {
  $hAdd = @{
    Apples=$howManyApples
    Oranges=$howManyOranges
  }
  $hToAdd = New-Object -TypeName PSObject -Property $hAdd;
  <# We have to call the ArrayList Add method to add to our dynamic object #>
  $object.Add($hToAdd) | Out-Null;
}

$a = New-Object -TypeName 'System.Collections.ArrayList';
$b = New-Object -TypeName 'System.Collections.ArrayList';
$a1 = @{
  Apples=3
  Oranges=2
}
$b1 = @{
  Apples=5
  Oranges=7
}
$a2 = @{
  Apples=6
  Oranges=3
}
$b2 = @{
  Apples=1
  Oranges=5
}
$aObject1 = New-Object -TypeName PSObject -Property $a1;
$bObject1 = New-Object -TypeName PSObject -Property $b1;
$aObject2 = New-Object -TypeName PSObject -Property $a2;
$bObject2 = New-Object -TypeName PSObject -Property $b2;
<# Here we call the ArrayList Add method #>
$a.Add($aObject1) | Out-Null; $a.Add($aObject2) | Out-Null;
$b.Add($bObject1) | Out-Null; $b.Add($aObject2) | Out-Null;

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Now lets make a trade`!";
Swap-Apples $a $b 0
Swap-Oranges $a $b 1

Write-Host "Values of A";
$a | Format-List

Write-Host "Values of B";
$b | Format-List

Write-Host "Hey, I brought more fruit for A`!";
Add-Fruit -object $a -howManyApples 5 -howManyOranges 2

Write-Host "Values of A";
$a | Format-List

Write-Host "I brought more fruit for B too`!";
Add-Fruit -object $b -howManyApples 5 -howManyOranges 3

Write-Host "Values of B";
$b | Format-List

Output:

Values of A


Oranges : 2
Apples  : 3

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 5

Oranges : 3
Apples  : 6



Now lets make a trade!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6



Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6



Hey, I brought more fruit for A!
Values of A


Oranges : 2
Apples  : 5

Oranges : 3
Apples  : 6

Oranges : 2
Apples  : 5



I brought more fruit for B too!
Values of B


Oranges : 7
Apples  : 3

Oranges : 3
Apples  : 6

Oranges : 3
Apples  : 5
Robert Smith
  • 309
  • 3
  • 10
0

It works to me:

Function Swap-Array ($theArrayA, $theArrayB, [int]$indexToSwap) 
{
  $temp = $theArrayA[$indexToSwap]
  $theArrayA[$indexToSwap] = $theArrayB[$indexToSwap]
  $theArrayB[$indexToSwap] = $temp
} 

$a = @(1,2,3,4)
$b = @(3,2,4,1)
$a
$b
Swap-Array $a $b 2
$a
$b

Just remove the comas.

fdafadf
  • 809
  • 5
  • 13