原始示例返回错误,因为数组创建为空,然后尝试访问第n个元素为其分配值。
这里有许多创造性的答案,许多我在阅读本文之前都不知道。对于一个小的数组,一切都很好,但是正如n0rd指出的那样,性能存在显着差异。
在这里,我使用Measure-Command来找出每次初始化需要多长时间。您可能会猜到,使用显式PowerShell循环的任何方法都比使用.Net构造函数或PowerShell运算符(将以IL或本机代码编译)的方法慢。
概要
New-Object
并且@(somevalue)*n
速度很快(100k元素大约需要20k滴答)。
- 使用范围运算符创建数组的
n..m
速度要慢10倍(200k滴答)。
- 与该
Add()
方法一起使用ArrayList的速度比基线(2000万个刻度)慢1000倍,使用for()
或ForEach-Object
(aka foreach
,%
)遍历一个已经大小的数组也是如此。
- 追加
+=
是最差的(仅1000个元素就有200万个滴答声)。
总的来说,我会说数组* n是“最佳”的,因为:
- 它很快。
- 您可以使用任何值,而不仅仅是类型的默认值。
- 您可以创建重复值(为说明起见,请在powershell提示符下输入:
(1..10)*10 -join " "
或('one',2,3)*3
)
- 简洁的语法。
唯一的缺点:
- 不明显。如果您以前没有看过此构造,则不清楚它的作用。
但是请记住,在许多情况下,您希望将数组元素初始化为某个值,那么正是您需要的是强类型数组。如果您将所有内容初始化为$false
,那么该数组是否会保留除$false
or以外的任何内容$true
?如果没有,那么New-Object type[] n
就是“最佳”方法。
测验
创建并调整默认数组的大小,然后分配值:
PS> Measure-Command -Expression {$a = new-object object[] 100000} | Format-List -Property "Ticks"
Ticks : 20039
PS> Measure-Command -Expression {for($i=0; $i -lt $a.Length;$i++) {$a[$i] = $false}} | Format-List -Property "Ticks"
Ticks : 28866028
创建布尔数组比对象数组和数组慢一点:
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
目前尚不清楚它的作用,New-Object的文档仅说第二个参数是传递给.Net对象构造函数的参数列表。对于数组,参数显然是所需的大小。
附加+ =
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
我已经厌倦了等待完成,所以按ctrl + c即可:
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Ticks : 147663
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 1000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Ticks : 2194398
就像(6 * 3)在概念上类似于(6 + 6 + 6)一样,($ somearray * 3)应该给出与($ somearray + $ somearray + $ somearray)相同的结果。但是对于数组,+是串联而不是加法。
如果$ array + = $ element较慢,则可能期望$ array * $ n也较慢,但事实并非如此:
PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks"
Ticks : 20131
就像Java有一个StringBuilder类来避免在添加时创建多个对象一样,PowerShell似乎具有ArrayList。
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 1000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 447133
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 10000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 2097498
PS> $al = New-Object System.Collections.ArrayList
PS> Measure-Command -Expression { for($i=0; $i -lt 100000; $i++) {$al.Add($false)} } | Format-List -Property "Ticks"
Ticks : 19866894
范围运算符和Where-Object
循环:
PS> Measure-Command -Expression { $a = 1..100000 } | Format-List -Property "Ticks"
Ticks : 239863
Measure-Command -Expression { $a | % {$false} } | Format-List -Property "Ticks"
Ticks : 102298091
笔记:
- 我在每次运行(
$a=$null
)之间使变量为空。
- 测试是在装有Atom处理器的平板电脑上进行的;您可能会在其他计算机上看到更快的速度。[编辑:在台式机上的速度大约是以前的两倍。]
- 当我尝试多次运行时,会有一些变化。寻找数量级而不是确切的数字。
- 测试是在Windows 8中使用PowerShell 3.0进行的。
致谢
感谢@ halr9000用于array * n,@Scott Saad和Lee Desmond用于New-Object,以及@EBGreen用于ArrayList。
感谢@ n0rd让我思考性能。