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
さらに別の選択肢:
for ($i = 0; $i -lt 5; $i++)
{
$arr += @($false)
}
これは、$ arrがまだ定義されていない場合に機能します。
NOTE-これを行うためのより良い(そしてよりパフォーマンスの高い)方法があります... https://stackoverflow.com/例としてa/234060/457 .
さらに2つの方法がありますが、どちらも非常に簡潔です。
$arr1 = @(0) * 20
$arr2 = ,0 * 20
型付き配列を作成する場合は、コンストラクタのデフォルト値を使用することもできます。
> $a = new-object bool[] 5
> $a
False
False
False
False
False
boolのデフォルト値は明らかにfalseなので、これはあなたのケースで機能します。同様に、型付きのint []配列を作成すると、デフォルト値の0が取得されます。
配列を初期化するために使用するもう1つのクールな方法は、次の速記を使用することです。
> $a = ($false, $false, $false, $false, $false)
> $a
False
False
False
False
False
または、範囲を初期化することができる場合、私はこれが役立つことが時々あります:
> $ a =(1..5) > $ a 1 2 3 4 5
これがいくらか役立つことを願っています!
元の例では、配列が空で作成されているためエラーが返されます。次に、n番目の要素にアクセスして値を割り当てようとします。
ここには多くの創造的な答えがありますが、多くはこの投稿を読む前に知りませんでした。小さなアレイにはすべて問題ありませんが、n0rdが指摘するように、パフォーマンスに大きな違いがあります。
ここでは、Measure-Commandを使用して、各初期化にかかる時間を調べます。ご想像のとおり、明示的なPowerShellループを使用するアプローチは、.NetコンストラクターまたはPowerShell演算子(ILまたはネイティブコードでコンパイルされる)を使用するアプローチよりも低速です。
New-Object
と@(somevalue)*n
は高速です(10万個の要素に対して約2万ティック)。n..m
を使用して配列を作成すると、10倍遅くなります(20万ティック)。Add()
メソッドでArrayListを使用すると、for()
またはForEach-Object
(別名foreach
、%
)。+=
を追加するのが最悪です(要素が1000個の場合は200万ティック)。全体的に、私は言うだろう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
ブールの配列の作成は、オブジェクトの配列よりも少し遅くなります。
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
これが何をするのかは明らかではありません。New-Objectのドキュメントでは、2番目のパラメーターは.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
)。Array * nの@ halr9000、New-Objectの@Scott SaadとLee Desmond、ArrayListの@EBGreenに感謝します。
パフォーマンスについて考えさせてくれた@ n0rdに感謝します。
$array = 1..5 | foreach { $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()
を使用すると、1つの明確な利点があります。ISEでプログラミングしているときにオブジェクトを作成する場合、ISEはすべてのパラメーターの組み合わせとそのタイプのヒントを提供します。 New-Object
では、引数のタイプと順序を覚えておく必要があります。
$array = @()
for($i=0; $i -lt 5; $i++)
{
$array += $i
}
私が見つけた解決策は、New-Objectコマンドレットを使用して適切なサイズの配列を初期化することでした。
$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)
}
または、これを考えてみてください。 powershell 5.0以降で動作します。
[bool[]]$tf=((,$False)*5)