I've found some interesting behaviour in PowerShell Arrays, namely, if I declare an array as:
$array = @()
And then try to add items to it using the $array.Add("item")
method, I receive the following error:
Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."
However, if I append items using $array += "item"
, the item is accepted without a problem and the "fixed size" restriction doesn't seem to apply.
Why is this?
When using the $array.Add()
-method, you're trying to add the element into the existing array. An array is a collection of fixed size, so you will receive an error because it can't be extended.
$array += $element
creates a new array with the same elements as old one + the new item, and this new larger array replaces the old one in the $array
-variable
You can use the += operator to add an element to an array. When you use it, Windows PowerShell actually creates a new array with the values of the original array and the added value. For example, to add an element with a value of 200 to the array in the $a variable, type: $a += 200
Source: about_Arrays
+=
is an expensive operation, so when you need to add many items you should try to add them in as few operations as possible, ex:
$arr = 1..3 #Array
$arr += (4..5) #Combine with another array in a single write-operation
$arr.Count
5
If that's not possible, consider using a more efficient collection like List
or ArrayList
(see the other answer).
If you want a dynamically sized array, then you should make a list. Not only will you get the .Add()
functionality, but as @frode-f explains, dynamic arrays are more memory efficient and a better practice anyway.
And it's so easy to use.
Instead of your array declaration, try this:
$outItems = New-Object System.Collections.Generic.List[System.Object]
Adding items is simple.
$outItems.Add(1)
$outItems.Add("hi")
And if you really want an array when you're done, there's a function for that too.
$outItems.ToArray()
Add()
function? I can confirm, if you create a generic List
object as stated above, you have a mutable list for which you can add and remove items using the Add()
and Remove()
methods respectively.
(New-Object System.Collections.Generic.List[string]).GetType().Name
yields List`1
for me, as expected; perhaps you applied +=
to the variable containing the list (rather than calling the .Add()
method), in which case the variable value would indeed be converted to an array (System.Object[]
).
$a = new-object collections.generic.list[object]
$arr = New-Object System.Collections.ArrayList
?
The most common idiom for creating an array without using the inefficient +=
is something like this, from the output of a loop:
$array = foreach($i in 1..10) {
$i
}
$array
Adding to a preexisting array:
[collections.arraylist]$array = 1..10
$array.add(11) > $null
Success story sharing
List
orArrayList
. They will be much faster. I personally use+=
and array 99% of the time because I usually create short throw-away scripts where the extra seconds doesn't matter. For big scripts with lots of add/remove where I want to optimize and save time I useList
orArrayList
.Add()
method exists?IList
. TryGet-Member -InputObject @()
will show thisAdd Method int IList.Add(System.Object value)
.Add()
because they implement IList, but it doesn't work because they are.IsFixedSize
. So why are they fixed size?? Why does IList have an property to check for a fixed size list thing?