PowerShell从数组中删除项[0]

时间:2022-08-26 14:11:57

I'm struggling a bit to remove the first line (item ID) of an array.

我很难删除数组的第一行(项目ID)。

$test.GetType()

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

To list all the options I tried ,$test | gm and it clearly states:

为了列出我尝试过的所有选项,$test | gm,它清楚地指出:

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

So when I try $test.RemoveAt(0) I get the error:

因此,当我尝试$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

So I finally found here that my array needs to be of the type System.Object to be able to use $test.RemoveAt(0). Is it best practice to declare all the arrays in the beginning of the script as a list? Or is it better to convert the arrays with $collection = ({$test}.Invoke()) to a list later on when this functionality is needed?

所以我最终发现我的数组需要是类型系统。对象可以使用$test.RemoveAt(0)。将脚本开头的所有数组声明为列表是最佳实践吗?或者,当需要这个功能时,使用$collection = ({$test}.Invoke())将数组转换为列表会更好吗?

What are the pro's and cons of both types? Thank you for your help.

两种类型的正反两面是什么?谢谢你的帮助。

7 个解决方案

#1


16  

Arrays are fixed-size, like the error says. RemoveAt() is an inherited method that doesn't apply to normal arrays. To remove the first entry in the array, you could overwrite the array by a copy that includes every item except the first, like this:

数组是固定大小的,就像错误说的那样。RemoveAt()是一个继承的方法,不适用于普通数组。要删除数组中的第一个条目,可以通过包含除第一个项以外的所有项的副本覆盖数组,如下所示:

$arr = 1..5

$arr
1
2
3
4
5

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

$arr
2
3
4
5

If you need to remove values at different indexes then you should consider using a List. It supports Add(), Remove() and RemoveAt():

如果需要删除不同索引上的值,那么应该考虑使用列表。它支持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

See my earlier SO answer and about_Arrays for more details about how arrays work.

有关数组如何工作的更多细节,请参见我前面的SO answer和about_Arrays。

#2


8  

This will allow you to remove every occurrence of an arbitrary element from an array without resorting to a more sophisticated .NET object.

这将允许您从数组中删除任意元素的每次出现,而不必求助于更复杂的。net对象。

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

This will do the same, but will only remove one of the elements. If there are duplicates, they will remain.

这样做也是一样的,但只会删除其中的一个元素。如果有重复,它们将会保留。

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

#3


3  

Just to update - there's an issue with @Frode F. answer

更新一下,@Frode f的回复有问题

If the number of elements in array is more than 1

如果数组中的元素个数大于1

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

If the number of elements is 1, then this doesn't remove the element

如果元素的数量是1,那么这不会删除元素

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

#4


2  

I think it's going to depend on the circumstances. If you only need to remove that first element once, then you can use array slicing:

我认为这将取决于具体情况。如果只需要删除第一个元素,那么可以使用数组切片:

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

If you're going to do it repeatedly, then you should start with an arraylist or generic collection. If it's a large array, you might want to just put the expression that's creating it into a scriptblock and do an .invoke() on that rather than letting the pipeline create an array and then convert that to a collection.

如果要重复执行,那么应该从arraylist或泛型集合开始。如果是一个大数组,您可能只想将创建它的表达式放入scriptblock中,并对其执行.invoke()操作,而不是让管道创建一个数组,然后将其转换为集合。

#5


2  

You can use Select-Object -Skip <count> to omit the first count item(s):

可以使用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:\>

#6


0  

Excuse the late answer, but I was struggling with this also. For my intents and purposes (writing to a text file), I realized that since the array was a fixed size -- instead of removing it I could just set the value to string.empty.

请原谅我迟来的回答,但我也在纠结这个问题。出于我的意图和目的(写入文本文件),我意识到由于数组的大小是固定的,所以我可以将值设置为string.empty。

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

For me this got rid of the header that I didn't want in my flat file. Hope this helps someone else out there.

对我来说,这消除了我不希望在我的平面文件中的标题。希望这能帮助别人。

#7


0  

If we have the case when big array(or ArrayList) must be performed by some parts - I used some lifehack:

如果我们遇到大数组(或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
}

And now we can handle big array by some parts(by 100 items)

现在我们可以处理大数组的一些部分(100个项目)

#1


16  

Arrays are fixed-size, like the error says. RemoveAt() is an inherited method that doesn't apply to normal arrays. To remove the first entry in the array, you could overwrite the array by a copy that includes every item except the first, like this:

数组是固定大小的,就像错误说的那样。RemoveAt()是一个继承的方法,不适用于普通数组。要删除数组中的第一个条目,可以通过包含除第一个项以外的所有项的副本覆盖数组,如下所示:

$arr = 1..5

$arr
1
2
3
4
5

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

$arr
2
3
4
5

If you need to remove values at different indexes then you should consider using a List. It supports Add(), Remove() and RemoveAt():

如果需要删除不同索引上的值,那么应该考虑使用列表。它支持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

See my earlier SO answer and about_Arrays for more details about how arrays work.

有关数组如何工作的更多细节,请参见我前面的SO answer和about_Arrays。

#2


8  

This will allow you to remove every occurrence of an arbitrary element from an array without resorting to a more sophisticated .NET object.

这将允许您从数组中删除任意元素的每次出现,而不必求助于更复杂的。net对象。

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

This will do the same, but will only remove one of the elements. If there are duplicates, they will remain.

这样做也是一样的,但只会删除其中的一个元素。如果有重复,它们将会保留。

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

#3


3  

Just to update - there's an issue with @Frode F. answer

更新一下,@Frode f的回复有问题

If the number of elements in array is more than 1

如果数组中的元素个数大于1

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

If the number of elements is 1, then this doesn't remove the element

如果元素的数量是1,那么这不会删除元素

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

#4


2  

I think it's going to depend on the circumstances. If you only need to remove that first element once, then you can use array slicing:

我认为这将取决于具体情况。如果只需要删除第一个元素,那么可以使用数组切片:

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

If you're going to do it repeatedly, then you should start with an arraylist or generic collection. If it's a large array, you might want to just put the expression that's creating it into a scriptblock and do an .invoke() on that rather than letting the pipeline create an array and then convert that to a collection.

如果要重复执行,那么应该从arraylist或泛型集合开始。如果是一个大数组,您可能只想将创建它的表达式放入scriptblock中,并对其执行.invoke()操作,而不是让管道创建一个数组,然后将其转换为集合。

#5


2  

You can use Select-Object -Skip <count> to omit the first count item(s):

可以使用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:\>

#6


0  

Excuse the late answer, but I was struggling with this also. For my intents and purposes (writing to a text file), I realized that since the array was a fixed size -- instead of removing it I could just set the value to string.empty.

请原谅我迟来的回答,但我也在纠结这个问题。出于我的意图和目的(写入文本文件),我意识到由于数组的大小是固定的,所以我可以将值设置为string.empty。

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

For me this got rid of the header that I didn't want in my flat file. Hope this helps someone else out there.

对我来说,这消除了我不希望在我的平面文件中的标题。希望这能帮助别人。

#7


0  

If we have the case when big array(or ArrayList) must be performed by some parts - I used some lifehack:

如果我们遇到大数组(或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
}

And now we can handle big array by some parts(by 100 items)

现在我们可以处理大数组的一些部分(100个项目)