原始示例返回错误,因为数组创建为空,然后您尝试访问第 n 个元素为其分配一个值。
这里有许多创造性的答案,很多我在阅读这篇文章之前并不知道。对于小型阵列来说,一切都很好,但正如 n0rd 指出的那样,性能存在显着差异。
在这里,我使用 Measure-Command 来了解每次初始化需要多长时间。正如您可能猜到的那样,任何使用显式 PowerShell 循环的方法都比使用 .Net 构造函数或 PowerShell 运算符(将在 IL 或本机代码中编译)的方法慢。
总结
-
New-Object 和 @(somevalue)*n 很快(100k 个元素大约 20k 个滴答声)。
- 使用范围运算符
n..m 创建数组的速度要慢 10 倍(200k 滴答声)。
- 使用带有
Add() 方法的ArrayList 比基线(20M 滴答声)慢1000 倍,就像使用for() 或ForEach-Object(又名foreach,%)循环一个已经大小的数组一样.
- 附加
+= 是最差的(仅 1000 个元素的 2M 滴答声)。
总的来说,我会说 array*n 是“最好的”,因为:
- 速度很快。
- 您可以使用任何值,而不仅仅是类型的默认值。
- 您可以创建重复值(为了说明,请在 powershell 提示符下键入:
(1..10)*10 -join " " 或 ('one',2,3)*3)
- 语法简洁。
唯一的缺点:
- 不明显。如果你以前没有见过这个结构,那么它的作用就不清楚了。
但请记住,在许多情况下,您希望将数组元素初始化为某个值,那么强类型数组正是您所需要的。如果您将所有内容初始化为$false,那么该数组是否会保存$false 或$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 让我思考性能问题。