PowerShellarrays初始化

在PowerShell中初始化数组的最佳方法是什么?

例如,代码

$array = @() for($i=0; $i -lt 5;$i++) { $array[$i] = $FALSE } 

生成错误

 Array assignment failed because index '0' was out of range. At H:\Software\PowerShell\TestArray.ps1:4 char:10 + $array[$ <<<< i] = $FALSE 

还有另一种select:

 for ($i = 0; $i -lt 5; $i++) { $arr += @($false) } 

如果$ arr尚未定义,这个工作。

这里有两种方法,都非常简洁。

 $arr1 = @(0) * 20 $arr2 = ,0 * 20 

如果你想创build一个types数组,你也可以依赖构造函数默认值

 > $a = new-object bool[] 5 > $a False False False False False 

布尔的默认值显然是错误的,所以这在你的情况下工作。 同样,如果你创build一个types化的int []数组,你将得到默认值0。

我用来初始化数组的另一个很酷的方法是用下面的简写:

 > $a = ($false, $false, $false, $false, $false) > $a False False False False False 

或者,如果你想要初始化一个范围,我有时会发现这是有用的:

 > $ a =(1..5)   
 > $ a
 1
 2
 3
 4
五

希望这有些帮助!

最初的例子返回一个错误,因为数组被创build为空,那么您尝试访问第n个元素来为其分配一个值。

这里有很多有创意的答案,很多我在阅读这篇文章之前都不知道。 对于一个小arrays来说都是好的,但是正如所指出的那样,在性能上存在显着的差异。

在这里我使用Measure-Command来确定每个初始化需要多长时间。 正如你可能猜到的那样,任何使用显式PowerShell循环的方法比那些使用.Net构造函数或PowerShell操作符(可以用IL或本地代码编译)的方法要慢。

概要

  • New-Object@(somevalue)*n是快速的(对于100k元素,大约20k)。
  • 使用范围运算符n..m创build一个数组要慢10倍(20万次)。
  • 与使用Add()方法的ArrayList相比,使用for()ForEach-Object (又名foreach% )循环已经大小的数组的速度是基线(20M ticks)的1000倍。
  • +=追加是最差的(只有1000个元素,为2M)。

总的来说,我会说arrays * n是“最好的”,因为:

  • 它很快。
  • 您可以使用任何值,而不仅仅是types的默认值。
  • (1..10)*10 -join " "('one',2,3)*3 )可以创build重复的值
  • Terse语法。

唯一的缺点:

  • 非显而易见的。 如果你之前没有看过这个构造,那么它的function并不明显。

但请记住,对于很多情况下,如果您想将数组元素初始化为某个值,那么强types数组正是您所需要的。 如果你把所有东西初始化为$false ,那么这个数组是否会持有除$false$true以外的任何东西? 如果不是,那么New-Object type[] n是“最好”的方法。

testing

创build并设置默认数组的大小,然后分配值:

 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 

创build一个布尔数组比Object和Object数组慢一点:

 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 + = $元素很慢,你可能会希望$ array * $ n也很慢,但不是:

 PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks" Ticks : 20131 

就像Java有一个StringBuilder类,以避免追加时创build多个对象,所以看起来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 

Range运算符和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 

笔记:

  • 我在每次运行之间消除了variables( $a=$null )。
  • Atom处理器在平板电脑上进行testing; 你可能会在其他机器上看到更快的速度。 [编辑:在台式机上快两倍]
  • 当我尝试多次运行时,有一些变化。 寻找数量级,而不是确切的数字。
  • 在Windows 8中使用PowerShell 3.0进行testing。

致谢

感谢@ halr9000的数组* n,@Scott Saad和Lee Desmond的New-Object,以及@EBGreen的ArrayList。

感谢@ n0rd让我思考性能。

 $array = 1..5 | foreach { $false } 
 $array = @() for($i=0; $i -lt 5; $i++) { $array += $i } 

我find的解决scheme是使用New-Object cmdlet来初始化一个适当大小的数组。

 $array = new-object object[] 5 for($i=0; $i -lt $array.Length;$i++) { $array[$i] = $FALSE } 

这是另一个想法。 你必须记住,它是下面的.NET:

 $arr = [System.Array]::CreateInstance([System.Object], 5) $arr.GetType() $arr.Length $arr = [Object[]]::new(5) $arr.GetType() $arr.Length 

结果:

 IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array 5 True True Object[] System.Array 5 

使用new()有一个明显的优点:当你在ISE中编程并且想要创build一个对象时,ISE会给你所有的paramer组合及其types的提示。 你没有New-Object ,你必须记住参数的types和顺序。

新的对象的ISE智能感知

如果我不知道大小,我使用arraylist而不是数组。

 $al = New-Object System.Collections.ArrayList for($i=0; $i -lt 5; $i++) { $al.Add($i) }