How to efficiently populate an array in Powershell

I want to fill up a dynamic array with the same integer value as quickly as possible using Powershell.
The Measure-Command command shows that it takes 7 seconds for my system to fill it.
My current code (snipped) looks like this:

$myArray = @() $length = 16385 for ($i=1;$i -le $length; $i++) {$myArray += 2} 

(The full code can be seen on gist.github.com or on superuser )

Consider what $length can change. But for a better understanding, I chose a fixed length.

Q: How to speed up this Powershell code?

+6
source share
4 answers

You can repeat arrays the same way you can do with strings:

 $myArray = ,2 * $length 

This means "Take an array with a single element 2 and repeat it $length times, getting a new array."

Note that you cannot use this to create multidimensional arrays, because the following:

 $some2darray = ,(,2 * 1000) * 1000 

It will simply create 1000 references to the internal array, which makes them useless for manipulation. In this case, you can use a hybrid strategy. I used

 $some2darray = 1..1000 | ForEach-Object { ,(,2 * 1000) } 

in the past but below performance measurements show that

 $some2darray = foreach ($i in 1..1000) { ,(,2 * 1000) } 

will be much faster.


Some performance measurements:

 Command Average Time (ms) ------- ----------------- $a = ,2 * $length 0,135902 # my own [int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length) 7,15362 # JPBlanc $a = foreach ($i in 1..$length) { 2 } 14,54417 [int[]]$a = -split "2 " * $length 24,867394 $a = for ($i = 0; $i -lt $length; $i++) { 2 } 45,771122 # Ansgar $a = 1..$length | %{ 2 } 431,70304 # JPBlanc $a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 } 10425,79214 # original code 

Taken by running each option 50 times through the Measure-Command , each with the same value for $length and averaging the results.

Positions 3 and 4 are actually a bit of a surprise. This seems to be much better than range foreach instead of the usual for loop.


The code to create the chart above is:

 $length = 16384 $tests = '$a = ,2 * $length', '[int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length)', '$a = for ($i = 0; $i -lt $length; $i++) { 2 }', '$a = foreach ($i in 1..$length) { 2 }', '$a = 1..$length | %{ 2 }', '$a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 }', '[int[]]$a = -split "2 " * $length' $tests | ForEach-Object { $cmd = $_ $timings = 1..50 | ForEach-Object { Remove-Variable i,a -ErrorAction Ignore [GC]::Collect() Measure-Command { Invoke-Expression $cmd } } [pscustomobject]@{ Command = $cmd 'Average Time (ms)' = ($timings | Measure-Object -Average TotalMilliseconds).Average } } | Sort-Object Ave* | Format-Table -AutoSize -Wrap 
+14
source

Avoid adding to an array in a loop. It copies the existing array to a new array with each iteration. Do this instead:

 $MyArray = for ($i=1; $i -le $length; $i++) { 2 } 
+5
source

Using PowerShell 3.0, you can use (.NET Framework 3.5 or top required):

 [int[]]$MyArray = ([System.Linq.Enumerable]::Repeat(2, 65000)) 

Using PowerShell 2.0

 $AnArray = 1..65000 | % {2} 
+3
source

It is unclear what you are trying. I tried to take a look at your code. But $myArray +=2 means that you just add 2 as an element. For example, here is the result of my test code:

 $myArray = @() $length = 4 for ($i=1;$i -le $length; $i++) { Write-Host $myArray $myArray += 2 } 2 2 2 2 2 2 

Why do you need to repeatedly add 2 as an element of an array?

If you only want to fill in the same value, try the following:

 $myArray = 1..$length | % { 2 } 
+1
source

Source: https://habr.com/ru/post/950334/


All Articles