80

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
4

12 に答える 12

99

さらに2つの方法がありますが、どちらも非常に簡潔です。

$arr1 = @(0) * 20
$arr2 = ,0 * 20
于 2008-10-24T15:40:20.080 に答える
54

型付き配列を作成する場合は、コンストラクターのデフォルト値に依存することもできます。

> $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

これが多少役に立ったことを願っています!

于 2008-10-22T18:14:22.027 に答える
47

さらに別の選択肢:

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

これは、$arrがまだ定義されていない場合に機能します。

-これを行うには、より良い(そしてよりパフォーマンスの高い)方法があります...例として、以下のhttps://stackoverflow.com/a/234060/4570を参照してください。

于 2008-10-22T16:46:49.240 に答える
41

元の例では、配列が空で作成され、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 に感謝します。

于 2015-01-18T21:55:54.160 に答える
13
$array = 1..5 | foreach { $false }
于 2008-10-23T15:30:30.190 に答える
11
$array = @()
for($i=0; $i -lt 5; $i++)
{
    $array += $i
}
于 2008-10-22T16:48:28.473 に答える
11

ここに別のアイデアがあります。下に .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では、引数の型と順序を覚えておく必要があります。

新しいオブジェクトの ISE IntelliSense

于 2016-01-25T14:43:16.990 に答える
7

私が見つけた解決策は、New-Object コマンドレットを使用して、適切なサイズの配列を初期化することでした。

$array = new-object object[] 5 
for($i=0; $i -lt $array.Length;$i++)
{
    $array[$i] = $FALSE
}
于 2008-10-22T16:36:53.910 に答える
6

前もってサイズがわからない場合は、配列の代わりに arraylist を使用します。

$al = New-Object System.Collections.ArrayList
for($i=0; $i -lt 5; $i++)
{
    $al.Add($i)
}
于 2008-10-22T16:43:52.053 に答える