views:

208

answers:

2

I have the following PowerShell function that works well for any input except for 1. If I pass it an input of 1 it will return an array with two elements 1,1 instead of a single element which is itself an array of two elements (1,1).

Any ideas how I can make PowerShell return a jagged array with one element that is itself an array?

function getFactorPairs {
    param($n)
    $factorPairs = @()
    $maxDiv = [math]::sqrt($n)
    write-verbose "Max Divisor: $maxDiv"
    for($c = 1; $c -le $maxDiv; $c ++) {
        $o = $n / $c;
        if($o -eq [math]::floor($o)) {
            write-debug "Factor Pair: $c, $o"
            $factorPairs += ,@($c,$o) # comma tells powershell to add defined array as element in existing array instead of adding array elements to existing array
        }
    }
    return $factorPairs
}

Here is my test and it's output showing the problem. You can see that the first example (1 as input) is returning a length of 2 even though there was only one factor pair found. The second example (6 as input) is working properly and is returning a length of 2 with two factor pairs found.

~» (getFactorPairs 1).length  
   DEBUG: Factor Pair: 1, 1  
   2  

~» (getFactorPairs 6).length  
   DEBUG: Factor Pair: 1, 6  
   DEBUG: Factor Pair: 2, 3  
   2
+4  A: 

I tested this on the PowerShell V2 CTP on Windows XP, and saw the same results as the OP.

The problem appears to be PowerShell's habit of "flattening" collections as they're passed along the pipeline. A simple solution is to wrap the return value in an collection by prefacing the expression to be returned with the comma operator thus:

return ,$factorPairs

See Keith Hill's blog entry Effective PowerShell Item 8: Output Cardinality - Scalars, Collections and Empty Sets - Oh My! for a little more detail.

Hope this helps.

Dan Blanchard
+3  A: 

You are close. The problem you are running into is that PowerShell unrolls (flattens) the array when it is returned from the function. Use the comma operator to return the array as-is without unrolling it:

return ,$factorPairs

When there is only one element in the array, which is the case for inputs 1,2,3 and other primes, PowerShell unrolls the contents of the array into the output so each element (1,1) appears on the output. Why PowerShell unrolls both the outer and the inner array in this case - I don't know for sure. I suspect they do it because there are scenarios where folks would expect this behavior from PowerShell.

Keith Hill