Creating an array with large initial size in powershell
In PowerShell
you are correct in that +=
will destroy the old array and create a new array with the new items.
For working with a large collection of items i would highly recommend using the ArrayList
type from .NET as this is not a fixed size array so PowerShell
will not destroy it every time you add an item to it and i've found this to work better in my projects.
Using ArrayList
also means that you don't need to start with 10000 items. Because PowerShell
won't need to recreate your array every time, you can start with 0 and then add each item as it's needed instead of starting with 10000.
So in your script i would create an empty ArrayList
like so
[System.Collections.ArrayList]$arr = @()
and then when you need to add something to it just call .Add()
(You don't need to prepopulate the array with 10000 items, it will expand as you add items).
$arr.Add([int]0)
Your example using an ArrayList
:
[System.Collections.ArrayList]$arr = @()
for ($i = 1; $i -le 10000; $i++) {
$arr.Add([int]0)
}
Use New-Object
in this case:
PS> $arr = New-Object int[] 10000; $arr.length
10000
Or, in PSv5+, using the static new()
method on the type:
PS> $arr = [int[]]::new(10000); $arr.length
10000
These commands create a strongly typed array, using base type [int]
in this example.
If the use case allows it, this is preferable for reasons of performance and type safety.
If you need to create an "untyped" array the same way that PowerShell does ([System.Object[]]
), substitute object
for int
; e.g., [object[]]::new(10000)
; the elements of such an array will default to $null
.
TessellatingHeckler's helpful answer, however, shows a much more concise alternative that even allows you initialize all elements to a specific value.
Arrays have a fixed size; if you need an array-like data structure that you can preallocate and grow dynamically, see Bluecakes' helpful [System.Collections.ArrayList]
-based answer.
[System.Collections.ArrayList]
is the resizable analog to [System.Object[]]
, and its generic equivalent - which like the [int[]]
example above - allows you to use a specific type for performance and robustness (if feasible), is [System.Collections.Generic.List[<type>]]
, e.g.:
PS> $lst = [System.Collections.Generic.List[int]]::New(10000); $lst.Capacity
10000
Note that - as with [System.Collections.ArrayList]
- specifying an initial capacity (10000
, here) does not allocate the internally used array with that size right away - the capacity value is simply stored (and exposed as property .Capacity
), and an internal array with that capacity (internal size that leaves room for growth) is allocated on demand, when the first element is added to the list.
[System.Collections.Generic.List[<type>]]
's .Add()
method commendably does not produce output, whereas [System.Collections.ArrayList]
's does (it returns the index of the element that was just added).
# The non-generic ArrayList's .Add() produces (usually undesired) output.
PS> $al = [System.Collections.ArrayList]::new(); $al.Add('first elem')
0 # .Add() outputs the index of the newly added item
# Simplest way to suppress this output:
PS> $null = $al.Add('first elem')
# NO output.
# The generic List[T]'s .Add() does NOT produce output.
PS> $gl = [System.Collections.Generic.List[string]]::new(); $gl.Add('first elem')
# NO output from .Add()
Array literal multiplication:
$arr = @($null) * 10000