1

I use arrays of arrays in a Powershell script, however, sometimes, my array of arrays, actually contains only one array. For some reason, Powershell keeps replacing that array containing one array, by just one array. I don't get it, no other scripting / coding language I ever used has done that before.

Example, this is what I do not want:

PS C:\Users\> $a = @(@(123,456,789))
PS C:\Users\> $a[0]
123

This is what I want:

PS C:\Users\> $a = @(@(123,456,789), @())
PS C:\Users\> $a[0]
123
456
789

Why do I have to force an extra empty array for Powershell to consider my array of arrays as such when it only contains one array ? This is driving me nuts !

jdel
  • 41
  • 4
  • `$a = ,(123,456,789)` – user4003407 Apr 14 '16 at 10:18
  • Sorry if it sounds stupid, but could you explain this syntax ? Even the microsoft documentation is quite evasive https://technet.microsoft.com/en-us/library/hh847882.aspx – jdel Apr 14 '16 at 10:26
  • 1
    @jdel PowerShell is trying to be "helpful" by flattening 1-sized arrays so you don't accidentally end up with nested structures when you don't need them – Mathias R. Jessen Apr 14 '16 at 10:38

2 Answers2

3

You need to put a comma as the first item:

 $a = @(, @(123,456,789) )

The reason for this is that the comma is essentially the array construction parameters. This MSDN article has more information.

Sean
  • 60,939
  • 11
  • 97
  • 136
0

@() operator interpret its content as statements not as expression. Let us put explicit ;.

@(@(123,456,789;);)

What do you have here:

  1. 123,456,789 — binary comma operator create an array with three elements.
    Result: array [123,456,789].
  2. 123,456,789; — as expression in this statement return collection, PowerShell enumerate this collection and write collection's elements (not collection itself) to the pipeline.
    Result: three elements 123, 456 and 789 written to the pipeline.
  3. @(123,456,789;) — array subexpression operator collect all the items written to pipeline as result of invocation of nested statements and create array from them.
    Result: array [123,456,789].
  4. @(123,456,789;); — as expression in this statement return collection, PowerShell enumerate this collection and write collection's elements (not collection itself) to the pipeline.
    Result: three elements 123, 456 and 789 written to the pipeline.
  5. @(@(123,456,789;);) — array subexpression operator collect all the items written to pipeline as result of invocation of nested statements and create array from them.
    Result: array [123,456,789].

So, when you write @(collection), PowerShell return copy of collection, not collection wrapped into single element array. If you want to create array with single element, then you should use unary comma operator: ,expression. This will create single element array regardless of expression return collection or not.

Also, when you write @(a,b,c,etc), it is binary comma, who create array. Array subexpression operator just copy that array. But why do you need a copy? Is any reason, why you can not use original array? All you need for not making extra copy is just to omit @ character: (a,b,c,etc).

user4003407
  • 21,204
  • 4
  • 50
  • 60
  • Thanks, I understand the principle. I always used the @ for making arrays, because in about_Arrays it is called the array operator. My problem is i need to build an multidimensional array, that will always behave like such, wether there is one array, or multiple arrays in it. I played around with the comma operator, but I cannot get this right. – jdel Apr 14 '16 at 14:25
  • I feel really stupid not understanding this array thing, but these two examples are confusing me even more: PS C:\Users\> $a = ,(123,456),(789) PS C:\Users\> foreach ($b in $a[0]) {write-host "--> $b"} --> 123 456 PS C:\Users\> foreach ($b in $a[1]) {write-host "--> $b"} --> 789 PS C:\Users\> $a = ,(123,456) PS C:\Users\> foreach ($b in $a[0]) {write-host "--> $b"} --> 123 --> 456 PS C:\Users\> foreach ($b in $a[1]) {write-host "--> $b"} – jdel Apr 14 '16 at 14:34
  • @jdel Important thing here is that unary comma have higher precedence than binary comma. So that `,(123,456),(789)` is the same as `(,(123,456)),(789)`. In JSON notation it will look like `[[[123,456]],789]`. `$a[0]` will be `[[123,456]]`, `$a[0][0]` will be `[123,456]`, `$a[0][0][0]` will be `123`, `$a[0][0][1]` will be `456` and `$a[1]` will be `789`. – user4003407 Apr 14 '16 at 16:09