2013-07-26 17 views
6

Chcę wypełnić dynamiczną tablicę z tą samą wartością całkowitą tak szybko, jak to możliwe, używając Powershell.
Polecenie pomiaru pokazuje, że wypełnienie go zajmuje 7 sekund.
Mój obecny kod (ucięte) wygląda następująco:Jak wydajnie wypełnić tablicę Powershell

$myArray = @() 
$length = 16385 
for ($i=1;$i -le $length; $i++) {$myArray += 2} 

(Pełny kod widać na gist.github.com lub na superuser)

Uważają, że $length może się zmienić. Ale dla lepszego zrozumienia wybrałem stałą długość.

Pytanie: Jak przyspieszyć ten kod Powershell?

Odpowiedz

14

Można powtórzyć tablic, po prostu jak możesz zrobić z ciągami:

$myArray = ,2 * $length 

Oznacza to: »Weź tablicę z pojedynczym elementem 2 i powtórz ją raz za razem, $length, uzyskując nową tablicę.«.

Należy pamiętać, że tak naprawdę nie można wykorzystać do tworzenia wielowymiarowych tablic, ponieważ następujący:

$some2darray = ,(,2 * 1000) * 1000 

po prostu stworzyć 1000 odniesień do wewnętrznej tablicy, czyniąc je bezużytecznymi dla manipulacji. W takim przypadku możesz użyć strategii hybrydowej. Użyłem

$some2darray = 1..1000 | ForEach-Object { ,(,2 * 1000) } 

w przeszłości, ale pomiary wydajności poniżej sugerują, że

$some2darray = foreach ($i in 1..1000) { ,(,2 * 1000) } 

byłby znacznie szybszy sposób.


Niektóre pomiary skuteczności:

Zrobione przez uruchomienie każdego wariantu 50 razy przez Measure-Command, każdy o tej samej wartości dla $length oraz uśrednienie wyników
Command             Average Time (ms) 
-------             ----------------- 
$a = ,2 * $length             0,135902 # my own 
[int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length)   7,15362 # JPBlanc 
$a = foreach ($i in 1..$length) { 2 }        14,54417 
[int[]]$a = -split "2 " * $length        24,867394 
$a = for ($i = 0; $i -lt $length; $i++) { 2 }     45,771122 # Ansgar 
$a = 1..$length | %{ 2 }           431,70304 # JPBlanc 
$a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 }  10425,79214 # original code 

.

Pozycja 3 i 4 to w istocie zaskoczenie. Wygląda na to, że o wiele lepiej jest uzyskać wartość foreach niż zakres, zamiast używać normalnej pętli for.


kod, aby wygenerować wykres powyżej:

$length = 16384 

$tests = '$a = ,2 * $length', 
     '[int[]]$a = [System.Linq.Enumerable]::Repeat(2, $length)', 
     '$a = for ($i = 0; $i -lt $length; $i++) { 2 }', 
     '$a = foreach ($i in 1..$length) { 2 }', 
     '$a = 1..$length | %{ 2 }', 
     '$a = @(); for ($i = 0; $i -lt $length; $i++) { $a += 2 }', 
     '[int[]]$a = -split "2 " * $length' 

$tests | ForEach-Object { 
    $cmd = $_ 
    $timings = 1..50 | ForEach-Object { 
     Remove-Variable i,a -ErrorAction Ignore 
     [GC]::Collect() 
     Measure-Command { Invoke-Expression $cmd } 
    } 
    [pscustomobject]@{ 
     Command = $cmd 
     'Average Time (ms)' = ($timings | Measure-Object -Average TotalMilliseconds).Average 
    } 
} | Sort-Object Ave* | Format-Table -AutoSize -Wrap 
+0

+1 i akceptowane. '$ myArray =, 2 * 16385' działa w 0,01 s. – nixda

+0

+1 To niezły bieg! – JPBlanc

+0

+1 Zwięzłe, jasne, konstruktywne, wszechstronne i powtarzalne! (no, 4 na 5 c ...) –

1

Nie jest jasne, co próbujesz. Próbowałem spojrzeć na twój kod. Ale, $myArray +=2 oznacza, że ​​dodajesz 2 jako element. Na przykład tutaj jest wynik z mojego kodu testowego:

$myArray = @() 
$length = 4 
for ($i=1;$i -le $length; $i++) { 
    Write-Host $myArray 
    $myArray += 2 
} 

2 
2 2 
2 2 2 

Dlaczego musisz dodać 2 jako element tablicy tyle razy?

Jeśli chcesz to wystarczy wypełnić tę samą wartość, spróbuj tego:

$myArray = 1..$length | % { 2 } 
+1

On jest po prostu napełniania tablicę z jakąś wartość? wartość to "2" – JPBlanc

+0

Pytanie mówi, że chce wypełnić tablicę tą samą wartością całkowitą. Jego problemem jest to, że dołączanie do tablicy z '+ =' jest strasznie wolne. –

+0

Hmm! Zrozumiałem to. Ale dlaczego? Poszukaj lepszego sposobu na zrobienie czegoś, co nie jest potrzebne. W każdym razie może również użyć operatora zasięgu. – ravikanth

5

unikać dołączania do tablicy w pętli. Kopiuje istniejącą tablicę do nowej tablicy z każdą iteracją. Czy to w zamian:

$MyArray = for ($i=1; $i -le $length; $i++) { 2 } 
+0

+1 Dla wyjaśnienia. – JPBlanc

+0

+1 '$ MyArray = for ($ i = 1; $ i -le 16385; $ i ++) {2}' trwa 0,05 sekundy. znacznie szybciej niż moje 7s :) – nixda

3

Korzystanie PowerShell 3.0 można użyć (potrzebujesz .NET Framework 3.5 lub górna):

[int[]]$MyArray = ([System.Linq.Enumerable]::Repeat(2, 65000)) 

Korzystanie PowerShell 2.0

$AnArray = 1..65000 | % {2} 
+0

+1 '[int []] $ myArray = ([System.Linq.Obliczalne] :: Powtórz (2, 16385))' działa w 0,03s – nixda

Powiązane problemy