Array.Add vs + =

179

Я обнаружил интересное поведение в массивах PowerShell, а именно, если я объявлю массив следующим образом:

$array = @()

А затем попробуйте добавить элементы к нему с помощью $array.Add("item")метода, я получаю следующую ошибку:

Исключение вызывает «Добавить» с аргументом (ами) «1»: «Коллекция имела фиксированный размер».

Однако, если я добавляю элементы, используя $array += "item", элемент принимается без проблем, и ограничение «фиксированный размер», кажется, не применяется.

Почему это?

malgca
источник

Ответы:

254

При использовании $array.Add()-method вы пытаетесь добавить элемент в существующий массив. Массив - это коллекция фиксированного размера, поэтому вы получите сообщение об ошибке, поскольку его невозможно расширить.

$array += $elementсоздает новый массив с теми же элементами, что и старый + новый элемент, и этот новый больший массив заменяет старый в $array-variable

Вы можете использовать оператор + =, чтобы добавить элемент в массив. Когда вы используете его, Windows PowerShell фактически создает новый массив со значениями исходного массива и добавленного значения. Например, чтобы добавить элемент со значением 200 в массив в переменной $ a, введите:

    $a += 200

Источник: about_Arrays

+= это дорогостоящая операция, поэтому, когда вам нужно добавить много элементов, вы должны попытаться добавить их как можно меньше операций, например:

$arr = 1..3    #Array
$arr += (4..5) #Combine with another array in a single write-operation

$arr.Count
5

Если это невозможно, рассмотрите возможность использования более эффективной коллекции, например Listили ArrayList(см. Другой ответ).

Фроде Ф.
источник
Спасибо :) Думал, что это может быть что-то вроде этого, но думал, что это будет неэффективно с большими массивами, поэтому команда powershell делала что-то другое.
Malgca
6
это совершенно верно, это становится неэффективным с большими массивами, к сожалению, чтобы обойти это, вы должны использовать другой тип: powershell.org/wp/2013/09/16/…
Nacht
3
Это зависит. Если вы собираетесь добавлять и удалять много участников, тогда да, попробуйте Listили ArrayList. Они будут намного быстрее. Я лично использую +=и массив 99% времени, потому что я обычно создаю короткие одноразовые сценарии, где дополнительные секунды не имеют значения. Для больших скриптов с большим количеством операций добавления / удаления, где я хочу оптимизировать и сэкономить время, которое я использую Listили ArrayList.
Фроде Ф.
3
Поскольку массивы всегда имеют фиксированный размер, кто-нибудь знает, почему Add()существует метод?
JohnLBevan
4
Потому что он унаследован от IList. Попробуй Get-Member -InputObject @()покажет этоAdd Method int IList.Add(System.Object value)
Фроде Ф.
113

Если вам нужен массив динамического размера, то вам следует составить список. Вы не только получите.Add() функциональность, но, как объясняет @ frode-f, динамические массивы более эффективны при использовании памяти и, во всяком случае, лучше.

И это так просто в использовании.

Вместо объявления массива попробуйте это:

$outItems = New-Object System.Collections.Generic.List[System.Object]

Добавить предметы просто.

$outItems.Add(1)
$outItems.Add("hi")

И если вам действительно нужен массив, когда вы закончите, для этого тоже есть функция.

$outItems.ToArray()
Себастьян Качмарек
источник
1
Я попробовал это. Я создаю его, используя New-Object System.Collections.Generic.List [string], но затем, если я делаю .GetType, он говорит мне, что это массив.
Preza8
1
Вы пытались использовать Add()функцию? Я могу подтвердить, если вы создать общий Listобъект , как указано выше, у вас есть изменяемый список , для которого вы можете добавлять и удалять элементы , используя Add()и Remove()методы соответственно.
Величайший Бендер
1
@ Preza8: (New-Object System.Collections.Generic.List[string]).GetType().Nameурожайность List`1для меня, как и ожидалось; возможно, вы применили +=к переменной, содержащей список (вместо вызова .Add()метода), и в этом случае значение переменной действительно будет преобразовано в массив ( System.Object[]).
mklement0
Ярлык:$a = new-object collections.generic.list[object]
Андрей
4

Наиболее распространенная идиома для создания массива без использования неэффективного +=- это что-то вроде этого из вывода цикла:

$array = foreach($i in 1..10) { 
  $i
}
$array
js2010
источник