Arrays PowerShell阵列初始化

Arrays PowerShell阵列初始化,arrays,powershell,Arrays,Powershell,在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[$ <<<<

在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
数组分配失败,因为索引“0”超出范围。
在H:\Software\PowerShell\TestArray.ps1:4 char:10

+$array[$我找到的解决方案是使用New-Object cmdlet初始化一个大小合适的数组

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

如果我不知道前面的大小,我会使用arraylist而不是数组

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

还有另一种选择:

for ($i = 0; $i -lt 5; $i++) 
{ 
  $arr += @($false) 
}
如果尚未定义$arr,则此选项有效


注意-有更好(和更高性能)的方法来实现这一点…请参见下面的示例。

如果您希望创建类型化数组,还可以依赖构造函数的默认值:

$array = @()
for($i=0; $i -lt 5; $i++)
{
    $array += $i
}
> $a = new-object bool[] 5
> $a
False
False
False
False
False
bool的默认值显然是false,因此这在您的情况下有效。同样,如果您创建一个类型化的int[]数组,您将获得默认值0

我用来初始化数组的另一种很酷的方法是使用以下速记:

> $a = ($false, $false, $false, $false, $false)
> $a
False
False
False
False
False
或者,如果你想初始化一个范围,我有时会发现这很有用:

> $a = (1..5) > $a 1 2 3 4 5 >$a=(1..5) >一美元 1. 2. 3. 4. 5.
希望这有点帮助!

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

$array = 1..5 | foreach { $false }
$arr1 = @(0) * 20
$arr2 = ,0 * 20

原始示例返回一个错误,因为数组创建为空,然后尝试访问第n个元素以为其赋值

这里有许多创造性的答案,许多是我在阅读本文之前不知道的。对于一个小数组来说,这些答案都很好,但正如n0rd指出的,在性能上有很大的差异

在这里,我使用Measure命令来确定每次初始化需要多长时间。正如您可能猜到的,任何使用显式PowerShell循环的方法都比使用.Net构造函数或PowerShell运算符(将在IL或本机代码中编译)的方法慢

总结
  • 新对象
    @(somevalue)*n
    速度很快(对于100k元素,大约20k个刻度)
  • 使用范围操作符
    n..m
    创建数组的速度慢10倍(200k个刻度)
  • 使用带有
    Add()
    方法的ArrayList比基线慢1000倍(20米刻度),使用
    for()
    ForEach对象
    (也称为
    ForEach
    %
    )循环通过已经大小的数组也是如此
  • 添加
    +=
    是最糟糕的(只有1000个元素有2米的刻度)
总的来说,我认为数组*n是“最好的”,因为:

  • 很快
  • 您可以使用任何值,而不仅仅是类型的默认值
  • 您可以创建重复值(如需说明,请在powershell提示符下键入:
    (1..10)*10-join”“
    ('one',2,3)*3
  • 简洁的语法
唯一的缺点是:

  • 不明显。如果你以前没见过这个构造,它的功能就不明显了
但请记住,在许多情况下,如果您希望将数组元素初始化为某个值,那么强类型数组正是您所需要的。如果您将所有内容初始化为
$false
,那么该数组是否将保存除
$false
$true
以外的任何内容?如果不存在,则
新建Object类型[]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
这并不明显,新对象的文档只是说第二个参数是传递给.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代表新对象,感谢@EBGreen代表ArrayList


感谢@n0rd让我思考性能问题。

这里有另一个想法。你必须记住,它是.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中编程并想要创建一个对象时,ISE将为您提供所有参数组合及其类型的提示。在
new object
中,您没有这种提示,您必须记住参数的类型和顺序


或者试试这个主意。与powershell 5.0+配合使用

[bool[]]$tf=((,$False)*5)

以下是另一种典型的方式:

$array = for($i = 0; $i -le 4; $i++) { $false }

告诉我们您正试图实现的目标,也许我们能够为您提供更好的“惯用PowerShell”回答。我从来没有需要在PowerShell中重新创建数组。我没有看到任何人特别提到数组是不可变的。一旦创建,它们就无法修改。非常好,我今天早上试图解决这个问题,我认为你给出了初始化数组的最简洁的方法。谢谢。我的博客上有更多信息,其中有这个主题c2007年9月1日起