如何在Powershell中有效地填充数组

nix*_*xda 6 arrays powershell

我想使用Powershell尽可能快地填充具有相同整数值的动态数组.
Measure-Command显示我的系统需要7秒才能填满它.
我当前的代码(剪切)看起来像:

$myArray = @()
$length = 16385
for ($i=1;$i -le $length; $i++) {$myArray += 2}  
Run Code Online (Sandbox Code Playgroud)

(完整代码可以在gist.github.com超级用户上看到)

考虑一下$length可以改变.但为了更好地理解,我选择了固定长度.

问:如何加速此Powershell代码?

Joe*_*oey 14

您可以像使用字符串一样重复数组:

$myArray = ,2 * $length
Run Code Online (Sandbox Code Playgroud)

这意味着»使用单个元素获取数组2并重复$length一次,产生一个新数组.«

请注意,您无法真正使用它来创建多维数组,因为以下内容:

$some2darray = ,(,2 * 1000) * 1000
Run Code Online (Sandbox Code Playgroud)

将只创建1000个内部数组的引用,使它们无法进行操作.在这种情况下,您可以使用混合策略.我用过

$some2darray = 1..1000 | ForEach-Object { ,(,2 * 1000) }
Run Code Online (Sandbox Code Playgroud)

在过去,但低于性能测量表明

$some2darray = foreach ($i in 1..1000) { ,(,2 * 1000) }
Run Code Online (Sandbox Code Playgroud)

会是一个更快的方式.


一些性能测量:

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
Run Code Online (Sandbox Code Playgroud)

通过运行每个变体50次Measure-Command,每个变量具有相同的值$length,并对结果求平均值.

实际上,位置3和4有点令人惊讶.显然,foreach超过范围而不是使用正常for循环要好得多.


生成上图的代码:

$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
Run Code Online (Sandbox Code Playgroud)


Ans*_*ers 5

避免在循环中附加到数组.它在每次迭代时将现有数组复制到一个新数组.改为:

$MyArray = for ($i=1; $i -le $length; $i++) { 2 }
Run Code Online (Sandbox Code Playgroud)


JPB*_*anc 5

使用 PowerShell 3.0 您可以使用(需要 .NET Framework 3.5 或更高版本):

[int[]]$MyArray = ([System.Linq.Enumerable]::Repeat(2, 65000))
Run Code Online (Sandbox Code Playgroud)

使用 PowerShell 2.0

$AnArray = 1..65000 | % {2}
Run Code Online (Sandbox Code Playgroud)