Eri*_*ess 71 arrays powershell
在PowerShell中初始化数组的最佳方法是什么?
例如,代码
$array = @()
for($i=0; $i -lt 5;$i++)
{
$array[$i] = $FALSE
}
Run Code Online (Sandbox Code Playgroud)
生成错误
Array assignment failed because index '0' was out of range.
At H:\Software\PowerShell\TestArray.ps1:4 char:10
+ $array[$ <<<< i] = $FALSE
Run Code Online (Sandbox Code Playgroud)
hal*_*000 89
这里有两种方式,都非常简洁.
$arr1 = @(0) * 20
$arr2 = ,0 * 20
Run Code Online (Sandbox Code Playgroud)
Sco*_*aad 51
如果要创建类型化数组,还可以依赖构造函数的默认值:
> $a = new-object bool[] 5
> $a
False
False
False
False
False
Run Code Online (Sandbox Code Playgroud)
bool的默认值显然是假的,所以这适用于您的情况.同样,如果您创建一个类型化的int []数组,您将获得默认值0.
我用来初始化数组的另一个很酷的方法是使用以下简写:
> $a = ($false, $false, $false, $false, $false)
> $a
False
False
False
False
False
Run Code Online (Sandbox Code Playgroud)
或者,如果你想初始化一个范围,我有时会觉得这很有用:
> $a = (1..5) > $a 1 2 3 4 5
希望这有点帮助!
Dav*_*dro 43
另一种选择:
for ($i = 0; $i -lt 5; $i++)
{
$arr += @($false)
}
Run Code Online (Sandbox Code Playgroud)
如果$ arr尚未定义,则此方法有效.
注意 - 有更好(更高性能)的方法来执行此操作...请参阅下面的/sf/answers/16384231/作为示例.
Cel*_*Man 37
原始示例返回错误,因为数组创建为空,然后您尝试访问第n个元素以为其分配值.
这里有许多创造性的答案,很多我在阅读这篇文章之前都不知道.对于小阵列来说,一切都很好,但正如n0rd指出的那样,性能存在显着差异.
在这里,我使用Measure-Command来查找每次初始化需要多长时间.正如您可能猜到的,任何使用显式PowerShell循环的方法都比使用.Net构造函数或PowerShell运算符(将在IL或本机代码中编译)的方法慢.
New-Object
并且@(somevalue)*n
很快(对于100k元素,大约20k刻度). n..m
速度要慢10倍(200k刻度). Add()
方法比基线(20M蜱)慢1000倍,如使用通过一个已经大小的数组循环for()
或ForEach-Object
(又名foreach
,%
). +=
是最差的(仅1000个元素的2M滴答).总的来说,我会说array*n是"最好的",因为:
(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
Run Code Online (Sandbox Code Playgroud)
创建一个Boolean数组比Object的数组慢一点:
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
Run Code Online (Sandbox Code Playgroud)
这并不明显,New-Object的文档只是说第二个参数是一个参数列表,它被传递给.Net对象构造函数.在阵列的情况下,参数显然是所需的大小.
附加+ =
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Run Code Online (Sandbox Code Playgroud)
我厌倦了等待完成,所以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
Run Code Online (Sandbox Code Playgroud)
正如(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
Run Code Online (Sandbox Code Playgroud)
就像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
Run Code Online (Sandbox Code Playgroud)
范围运算符和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
Run Code Online (Sandbox Code Playgroud)
笔记:
$a=$null
)之间调整了变量.感谢@ halr9000 for array*n,@ Scott Saad和Lee Desmond为New-Object,@ EBGreen为ArrayList.
感谢@ n0rd让我考虑性能.
这是另一个想法.你必须记住,它是.NET下面的:
$arr = [System.Array]::CreateInstance([System.Object], 5)
$arr.GetType()
$arr.Length
$arr = [Object[]]::new(5)
$arr.GetType()
$arr.Length
Run Code Online (Sandbox Code Playgroud)
结果:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
5
True True Object[] System.Array
5
Run Code Online (Sandbox Code Playgroud)
使用new()
有一个明显的优势:当您在ISE中编程并想要创建一个对象时,ISE将为您提供所有paramer组合及其类型的提示.你没有那个New-Object
,你必须记住参数的类型和顺序.
我发现的解决方案是使用New-Object cmdlet初始化适当大小的数组.
$array = new-object object[] 5
for($i=0; $i -lt $array.Length;$i++)
{
$array[$i] = $FALSE
}
Run Code Online (Sandbox Code Playgroud)
如果我不知道前面的大小,我使用arraylist而不是数组.
$al = New-Object System.Collections.ArrayList
for($i=0; $i -lt 5; $i++)
{
$al.Add($i)
}
Run Code Online (Sandbox Code Playgroud)