Оригінальний приклад повертає помилку, оскільки масив створюється порожнім, тоді ви намагаєтесь отримати доступ до n-го елемента, щоб присвоїти йому значення.
Тут є ряд творчих відповідей, багато з яких я не знав до прочитання цього допису. Все добре для невеликого масиву, але, як зазначає n0rd, є суттєві відмінності в продуктивності.
Тут я використовую Measure-Command, щоб з’ясувати, скільки часу триває кожна ініціалізація. Як ви можете здогадатися, будь-який підхід, який використовує явний цикл PowerShell, є повільнішим, ніж той, який використовує конструктори .Net або оператори PowerShell (які будуть скомпільовані в IL або коді).
Резюме
New-Object
і @(somevalue)*n
швидкі (близько 20 тис. галочок на 100 тис. елементів).
- Створення масиву за допомогою оператора діапазону
n..m
відбувається в 10 разів повільніше (200 тис. Галочок).
- Використання ArrayList із
Add()
методом у 1000 разів повільніше базової лінії (20 мільйонів галочок), як і циклічне проходження масиву, що вже має розмір, за допомогою for()
або ForEach-Object
(aka foreach
, %
).
- Додавання символу
+=
- найгірше (2 мільйони галочок на 1000 елементів)
Загалом, я б сказав, що масив * 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
Створення масиву Boolean трохи повільніше ніж і масиву Object:
PS> Measure-Command -Expression {$a = New-Object bool[] 100000} | Format-List -Property "Ticks"
Ticks : 130968
Не очевидно, що це робить, документація для New-Object просто говорить, що другий параметр - це список аргументів, який передається конструктору об'єктів .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
).
- Тестування проводилося на планшеті з процесором Atom; ви, мабуть, бачили б швидкість на інших машинах. [редагувати: приблизно вдвічі швидше на настільному комп'ютері.]
- Коли я спробував кілька запусків, було досить багато змін. Шукайте порядки, а не точні цифри.
- Тестування проводилося за допомогою PowerShell 3.0 у Windows 8.
Подяка
Дякуємо @ halr9000 за масив * n, @Scott Saad та Lee Desmond для New-Object та @EBGreen за ArrayList.
Дякую @ n0rd за те, що я змусив задуматися про продуктивність.