Home > Back-end >  Understanding obscure PowerShell array syntax: Why does @(11..20 1) work while @(1 11..20) doesn
Understanding obscure PowerShell array syntax: Why does @(11..20 1) work while @(1 11..20) doesn

Time:02-27

Consider the following: (Note: I modified the output slightly for readability)

~> @(11..20)
11, 12, 13, 14, 15, 16, 17, 18, 19, 20

~> @(11..20 1)
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1

~> @(1 11..20)
InvalidOperation: Method invocation failed because [System.Object[]] does not contain a method named 'op_Addition'.

I've always found this array addition syntax to be confusing, and would much prefer something like @(1,11..20).

At any rate, why does the 3rd operation not work identically to the 2nd?

Is it because 1 is not considered an array, even though it is being given as part of the array definition syntax?

~> @(1,2 11..20)
1, 2, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

If that's the case then why does @(11..20 1) work as expected?

I can work around this in a few ways...

~> @(@(1) 11..20)
1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

~> @(,1 11..20)
1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

~> @(11..20 1) | Sort
1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

But those seem pretty ugly, inelegant, and the latter workaround doesn't account for instances where I don't actually want to sort the array.

The one that makes the most sense is @(,1 11..20), though it's not particularly pleasing. Is there a more proper way to achieve the desired result in the desired order, without the additional syntax or piping?

None of the examples in the official documentation demonstrate this particular permutation.

Thanks.

CodePudding user response:

@(...), PowerShell's array-subexpression operator - which enumerates whatever ... outputs and collects it in an [object[]] array - is only applied after ... is evaluated, so we can leave it aside in this discussion.

Generally, in PowerShell it is the type of the LHS of an operation that determines what type-appropriate overload of the operation applies.

  • In 11..20 1, the LHS is an array, due to use of .., the range operator, so the operator performs array concatenation.

  • In 1 11..20, the LHS is a scalar - an [int] instance - so the operator tries to perform numerical addition, which, however, fails, because adding an array to a number doesn't make sense and therefore isn't supported.

If you want to perform array concatenation with a scalar LHS, wrap that LHS in an aux. array using the unary form of ,, the array constructor operator:

, 1   11..20

Alternatively, use one of the following:

  • @(1) 11..20
  • [array] 1 11..20

If you don't know ahead of time whether the LHS actually is already an array, but you want it treat it as such if it isn't, the [array] cast is the most efficient solution:

[array] 1   11..20

Note that the cast only applies to 1, based on PowerShell's operator precedence rules.

  • Related