PowerShell удаляет элемент [0] из массива

Я немного борюсь, чтобы удалить первую строку (идентификатор элемента) массива.

$test.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                      
-------- -------- ----                                     --------                                                                                                      
True     True     Object[]                                 System.Array

чтобы перечислить все варианты, которые я пробовал ,$test | gm и в нем ясно говорится:

Remove         Method                void IList.Remove(System.Object value)                                                                                              
RemoveAt       Method                void IList.RemoveAt(int index)

поэтому, когда я попробовать $test.RemoveAt(0) Я получаю сообщение об ошибке:

Exception calling "RemoveAt" with "1" argument(s): "Collection was of a fixed size."At line:1 char:1
+ $test.RemoveAt(1)
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : NotSupportedException

так я, наконец, нашел здесь что мой массив должен быть типа System.Object чтобы использовать $test.RemoveAt(0). Рекомендуется ли объявлять все массивы в начале скрипта в виде списка? Или лучше обратить массивы с $collection = ({$test}.Invoke()) в Список позже, когда эта функция нужна?

каковы плюсы и минусы обоих типов? Спасибо за помощь.

7 ответов


массивы фиксированного размера, как говорится в ошибке. RemoveAt() является унаследованным методом,который не применяется к обычным массивам. Чтобы удалить первую запись в массиве, вы можете перезаписать массив копией, которая включает каждый элемент, кроме первого, например:

$arr = 1..5

$arr
1
2
3
4
5

$arr = $arr[1..($arr.Length-1)]

$arr
2
3
4
5

Если вам нужно удалить значения в разных индексах, вы должны рассмотреть возможность использования List. Он поддерживает Add(), Remove() и RemoveAt():

#If you only have a specific type of objects, like int, string etc. then you should edit `[System.Object] to [System.String], [int] etc.
$list = [System.Collections.Generic.List[System.Object]](1..5)

$list
1
2
3
4
5

$list.RemoveAt(0)

$list
2
3
4
5

см. мой предыдущий так что ответ и в разделе about_arrays для получения более подробной информации о том, как массивы работают.


Это позволит вам удалить каждое вхождение произвольного элемента из массива, не прибегая к более сложному объекту .NET.

$x=<array element to remove>
$test = $test | Where-Object { $_ -ne $test[$x] }

это сделает то же самое, но удалит только один из элементов. Если есть дубликаты, они останутся.

$x=<array element to remove>
$skip=$true
$test = $test | ForEach-Object { if (($_ -eq $x) -and $skip) { $skip=$false } else { $_ } }

просто обновить - есть проблема с @Frode F. ответ

Если количество элементов в массиве больше, чем 1

$arr = $arr[1..($arr.Length-1)]

Если количество элементов равно 1, то это не удалить элемент

if($arr.Length -le 1) {
    $arr = @()
}
else {
    $arr = $arr[1..($arr.length - 1)]
}

Я думаю, это будет зависеть от обстоятельств. Если вам нужно удалить этот первый элемент только один раз, вы можете использовать срез массива:

$arr = $arr[1..($arr.length-1)]

Если вы собираетесь делать это неоднократно, то вы должны начать с arraylist или generic collection. Если это большой массив, вы можете просто поместить выражение, которое его создает, в scriptblock и сделать .invoke() на этом, а не позволяя конвейеру создать массив, а затем преобразовать его в коллекция.


можно использовать Select-Object -Skip <count> пропустить первые графа товар(ов):

PS C:\> 1..3 | Select-Object -Skip 1
2
3
PS C:\>

PS C:\> 1 | Select-Object -Skip 1
PS C:\>

извините за поздний ответ, но я тоже боролся с этим. Для моих намерений и целей (запись в текстовый файл) я понял, что, поскольку массив был фиксированным размером, вместо его удаления я мог просто установить значение string.пустой.

$results = SQLQuery -connectionString $connectionString  -query $query;
$results[0] = '';
foreach ($r in $results) {
    Add-Content $skus $r[0]; 
}

для меня это избавилось от заголовка, который я не хотел в своем плоском файле. Надеюсь, это поможет кому-то еще.


Если у нас есть случай, когда большой массив (или ArrayList) должен выполняться некоторыми частями - я использовал некоторый lifehack:

#$bigArray with thousands of items
while($bigArray.Count -gt 0)
{
    if($bigArray.Count -gt 100)
    {
    $k = 100
    }else {$k = $bigArray.Count}
    $part = $bigArray | select -First $k
#now we can make some operations with this $part
#in the end of loop we should exclude this part from big array
    if($bigArray.Count -gt 100)
    {
        $bigArray = $bigArray | select -Last ($bigArray.Count - $k)
    }else {$bigArray = @()}#in this step we have been handle last part of array and we should null him for stop loop
}

и теперь мы можем обрабатывать большой массив на несколько частей(на 100 пунктов)