元の例では、配列が空で作成され、n 番目の要素にアクセスして値を代入しようとするため、エラーが返されます。
ここには多くの創造的な答えがありますが、その多くはこの投稿を読むまで知りませんでした. 小さな配列ではすべて問題ありませんが、n0rd が指摘するように、パフォーマンスには大きな違いがあります。
ここでは、Measure-Command を使用して、各初期化にかかる時間を調べます。ご想像のとおり、明示的な PowerShell ループを使用するアプローチは、.Net コンストラクターまたは PowerShell オペレーター (IL またはネイティブ コードでコンパイルされる) を使用するアプローチよりも遅くなります。
概要
New-Object@(somevalue)*n高速です (100k 要素に対して約 20k ティック) 。
- 範囲演算子を使用して配列を作成すると、
n..m10 倍遅くなります (200k ティック)。
- メソッドでArrayList を使用すると
Add()、ベースラインよりも 1000 倍遅くなります (20M ティック) 。for()またはForEach-Object(別名foreach, %) を使用して既にサイズが設定されている配列をループします。
- withの追加
+=は最悪です (わずか 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 のドキュメントには、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
ノート:
- 各実行間で変数を null にしました (
$a=$null)。
- テストは Atom プロセッサを搭載したタブレットで行われました。おそらく、他のマシンの方が高速であることがわかります。[編集: デスクトップ マシンの約 2 倍の速さ]
- 複数回試してみると、かなりの変動がありました。正確な数ではなく、桁数を探します。
- テストは、Windows 8 の PowerShell 3.0 で行われました。
謝辞
array*n の @halr9000、New-Object の @Scott Saad と Lee Desmond、ArrayList の @EBGreen に感謝します。
パフォーマンスについて考えさせてくれた @n0rd に感謝します。