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



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

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

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

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

Q:如何加速此Powershell代码?

您可以重复数组,就像处理字符串一样:

$myArray = ,2 * $length

这意味着»取具有单个元素2的数组,并将其重复$length次,生成一个新数组。«。

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

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

只会创建1000个对内部数组的引用,使它们对操作毫无用处。在这种情况下,您可以使用混合策略。我用过

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

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

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

这将是一个更快的方式。


一些性能测量:

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

通过在Measure-Command中运行每个变体50次,每个变体具有相同的$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

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

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

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

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

使用PowerShell 2.0

$AnArray = 1..65000 | % {2}

目前尚不清楚您在尝试什么。我试着查看了你的代码。但是,$myArray +=2意味着您只是添加了2作为元素。例如,以下是我的测试代码的输出:

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

为什么要多次添加2作为数组元素?

如果你只想填充相同的值,试试这个:

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

如果你真的很快需要它,那么就使用ArrayLists和Tuples:

$myArray = New-Object 'Collections.ArrayList'
$myArray = foreach($i in 1..$length) {
    [tuple]::create(2)
}

如果你以后需要排序,那么使用这个(通常慢一点):

$myArray = New-Object 'Collections.ArrayList'
foreach($i in 1..$length) {
    $myArray.add(
        [tuple]::create(2)
    )
}

两个版本对我来说都在20ms的范围内;-)

相关内容

  • 没有找到相关文章