Das ursprüngliche Beispiel gibt einen Fehler zurück, da das Array leer erstellt wurde. Anschließend versuchen Sie, auf das n-te Element zuzugreifen, um ihm einen Wert zuzuweisen.
Hier gibt es eine Reihe kreativer Antworten, viele, die ich vor dem Lesen dieses Beitrags nicht kannte. Alle sind für ein kleines Array in Ordnung, aber wie n0rd hervorhebt, gibt es signifikante Leistungsunterschiede.
Hier benutze ich Measure-Command, um herauszufinden, wie lange jede Initialisierung dauert. Wie Sie vielleicht erraten haben, ist jeder Ansatz, der eine explizite PowerShell-Schleife verwendet, langsamer als der, der .NET-Konstruktoren oder PowerShell-Operatoren verwendet (die in IL oder nativem Code kompiliert würden).
Zusammenfassung
New-Objectund @(somevalue)*nsind schnell (ca. 20.000 Ticks für 100.000 Elemente).
- Das Erstellen eines Arrays mit dem Bereichsoperator
n..mist 10x langsamer (200.000 Ticks).
- Die Verwendung einer ArrayList mit der
Add()Methode ist 1000-mal langsamer als die Basislinie (20 Millionen Ticks), ebenso wie das Durchlaufen eines bereits großen Arrays mit for()oder ForEach-Object(auch bekannt foreachals %).
- Das Anhängen mit
+=ist das Schlimmste (2 Millionen Ticks für nur 1000 Elemente).
Insgesamt würde ich sagen, Array * n ist "am besten", weil:
- Es ist schnell.
- Sie können einen beliebigen Wert verwenden, nicht nur den Standardwert für den Typ.
- Sie können sich wiederholende Werte erstellen (geben Sie dies zur Veranschaulichung an der Powershell-Eingabeaufforderung ein:
(1..10)*10 -join " "oder ('one',2,3)*3)
- Knappe Syntax.
Einziger Nachteil:
- Nicht offensichtlich. Wenn Sie dieses Konstrukt noch nicht gesehen haben, ist nicht ersichtlich, was es bewirkt.
Beachten Sie jedoch, dass in vielen Fällen, in denen Sie die Array-Elemente auf einen bestimmten Wert initialisieren möchten, ein stark typisiertes Array genau das ist, was Sie benötigen. Wenn Sie alles auf initialisieren $false, wird das Array dann jemals etwas anderes als $falseoder enthalten $true? Wenn nicht, dann New-Object type[] nist der "beste" Ansatz.
Testen
Erstellen und skalieren Sie ein Standardarray und weisen Sie dann Werte zu:
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
Das Erstellen eines Booleschen Arrays ist etwas langsamer als ein Array von Object:
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
Es ist nicht offensichtlich, was dies bewirkt. In der Dokumentation zu New-Object heißt es lediglich, dass der zweite Parameter eine Argumentliste ist, die an den .Net-Objektkonstruktor übergeben wird. Bei Arrays ist der Parameter offensichtlich die gewünschte Größe.
Anhängen mit + =
PS> $a=@()
PS> Measure-Command -Expression { for ($i=0; $i -lt 100000; $i++) {$a+=$false} } | Format-List -Property "Ticks"
Ich hatte es satt, darauf zu warten, also Strg + C dann:
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
So wie (6 * 3) konzeptionell (6 + 6 + 6) ähnlich ist, sollte ($ somearray * 3) das gleiche Ergebnis liefern wie ($ somearray + $ somearray + $ somearray). Bei Arrays ist + jedoch eher eine Verkettung als eine Addition.
Wenn $ array + = $ element langsam ist, können Sie erwarten, dass $ array * $ n auch langsam ist, aber es ist nicht:
PS> Measure-Command -Expression { $a = @($false) * 100000 } | Format-List -Property "Ticks"
Ticks : 20131
So wie Java über eine StringBuilder-Klasse verfügt, um zu vermeiden, dass beim Anhängen mehrere Objekte erstellt werden, scheint PowerShell über eine ArrayList zu verfügen.
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
Bereichsoperator und Where-ObjectSchleife:
PS> Measure-Command -Expression { $a = 1..100000 } | Format-List -Property "Ticks"
Ticks : 239863
Measure-Command -Expression { $a | % {$false} } | Format-List -Property "Ticks"
Ticks : 102298091
Anmerkungen:
- Ich habe die Variable zwischen jedem Lauf (
$a=$null) auf Null gesetzt .
- Das Testen erfolgte auf einem Tablet mit Atom-Prozessor. Sie würden wahrscheinlich schnellere Geschwindigkeiten auf anderen Maschinen sehen. [Bearbeiten: Auf einem Desktop-Computer ungefähr doppelt so schnell.]
- Es gab einiges an Abwechslung, als ich mehrere Läufe ausprobierte. Suchen Sie nach Größenordnungen und nicht nach exakten Zahlen.
- Das Testen erfolgte mit PowerShell 3.0 unter Windows 8.
Danksagung
Vielen Dank an @ halr9000 für Array * n, @ Scott Saad und Lee Desmond für New-Object und @EBGreen für ArrayList.
Vielen Dank an @ n0rd, dass ich über Leistung nachgedacht habe.