2

I have implemented a simple merge sort function in PowerShell like so

function Merge-Sort
{
  param($a)
  if ($a.Length -gt 1)
  {
    $m = [Math]::floor($a.Length / 2)
    [Int[]]$l = $a[0..($m-1)]
    [Int[]]$r = $a[$m..($a.Length)]

    Merge-Sort $l
    Merge-Sort $r

    $i = $j = $k = 0

    while ($i -lt $l.Length -and $j -lt $r.Length)
    {
      if ($l[$i] -lt $r[$j])
      {
        $a[$k] = $l[$i]
        $i++
      }
      else
      {
        $a[$k] = $r[$j]
        $j++
      }
      $k++
    }

    while($i -lt $l.length)
    {
        $a[$k] = $l[$i]
        $i++
        $k++
    }

    while($j -lt $r.length)
    {
        $a[$k] = $r[$j]
        $j++
        $k++
    }
 }
}

The functions does what it should and sorts an array of integer values:

 $arr = @(22,44,55,11,66,11,77,99,33,88)
 merge-sort $arr

The output is: 11 11 22 33 44 55 66 77 88 99

But when I define the function parameter as [Int[]] to make clear that it should be an array of integers instead of object something went wrong and the array stays unsorted:

 function Merge-Sort
 {
    param([Int[]]$a)
    ...
 }

The output is: 22 44 55 11 66 11 77 99 33 88

My question is:

Why does the correct way to define the function parameter leads to an incorrect result (the array does not get sorted)?

3
  • it's happening because you are passing the array in by reference, not by value in the 1st version. the 2nd version passes in the items by value ... and you DO NOT send out any output. [grin] ///// also, why are you sorting in that very, very freaky manner? there is a built in [array]::Sort() method that will do an in-place sort of an array. there is also a [array]::Reverse() in there for giggles. [grin] Commented Nov 4, 2018 at 22:33
  • Good point about the different call techniques - I wasn't sure about that. The function is just a kind of training exercise for my Algorithm class. So not having a return value is on purpose. Usually I would use something like Sort-Object. Commented Nov 4, 2018 at 22:50
  • thank you for the "why" of it all. the detailed [and more accurate] explanation by ArcSet is a really nice one ... noticeably better than mine. [grin] Commented Nov 4, 2018 at 23:08

1 Answer 1

2

When the object $arr is created since it wasn't defined as a int array [int[]] it was created as a [array]. When passed to the function originally before [int[]] was added. It passed the reference and changed the data. If you Added a addition object to the array it would have not returned anything ether since that would have created a new array object.

When you added the [int[]] to the parameter it created a brand new int array [int[]] object named $a and changed the data there. Since $a is never return the variable is killed at the end of the function.

If you passed a int array it would have manipulated that array.

Lets looks over a few examples

This will change the first value at index 0 to 5. Since no object was added to the array and the array can be any object in the parameter it allowed the reference to index 0 to be changed instead of a whole new object needing to be returned

function TestFunction($a)
{
    $a[0] = 5
}
$TestVar = @(2,3,1)
TestFunction -a $TestVar
$TestVar

output 5,3,1

Since the orignal object is type Array and the parameter is type int array. the function will create a new int array based on the input array. Since the function needs to return the new int array and there is no return it will be garbage collected.

function TestFunction([int[]]$a)
{
    $a[0] = 4
}
$TestVar = @(2,3,1)
TestFunction -a $TestVar
$TestVar

So in your case we can do

function TestFunction([int[]]$a)
{
  $a[0] = 4
}
[int[]]$TestVar = @(2,3,1)
TestFunction -a $TestVar
$TestVar

since the parameter is looking for a int array and the input is a int array and no new objects are being added or subtracted from the array it will change the value correctly.

Sign up to request clarification or add additional context in comments.

2 Comments

Great answer! I was thinking about using [Ref] but your solution looks easier and more solid as well.
So in the end I was only forgetting to declare the array explicitly as Int[[]]...

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.