PowerShell从数组中删除项[0]

Dar*_*te1 15 arrays powershell arraylist

我正在努力去除数组的第一行(项ID).

$test.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                      
-------- -------- ----                                     --------                                                                                                      
True     True     Object[]                                 System.Array
Run Code Online (Sandbox Code Playgroud)

列出我尝试的所有选项,$test | gm,它清楚地说明:

Remove         Method                void IList.Remove(System.Object value)                                                                                              
RemoveAt       Method                void IList.RemoveAt(int index)
Run Code Online (Sandbox Code Playgroud)

所以,当我尝试时,$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
Run Code Online (Sandbox Code Playgroud)

所以我终于在这里发现我的数组需要System.Object是能够使用的类型$test.RemoveAt(0).最佳做法是将脚本开头的所有数组声明为列表吗?或者$collection = ({$test}.Invoke()),如果需要此功能,最好将数组转换为列表?

这两种类型的优点和缺点是什么?谢谢您的帮助.

Fro*_* F. 22

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

$arr = 1..5

$arr
1
2
3
4
5

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

$arr
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

如果您需要删除不同索引的值,那么您应该考虑使用a 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
Run Code Online (Sandbox Code Playgroud)

有关数组如何工作的更多详细信息,请参阅我之前的SO答案about_Arrays.

  • 我建议使用 `$arr[1..$arr.length]`,这不仅更短,而且在 `$arr` 只有一个元素的情况下效果更好。那么你的方法不会剥离该元素,而这个方法会剥离该元素。 (3认同)
  • `$arr[1..($arr.Length-1)]` 不适用于长度为 1 的数组(人们期望它返回空数组,但事实并非如此)。如果这可能是一个问题,请使用它: `$upperBound = (1, ($args.length-1) |measure-object -max).maximum; $userProvidedArgs = $args[1..$upperBound]` (2认同)

小智 14

另一种选择是使用Powershell分配多个变量的能力(请参阅https://docs.microsoft.com/en-gb/powershell/module/microsoft.powershell.core/about/about_assignment_operators?view=powershell-分配多个变量 - 由于这个答案,我找到了5.1:https://stackoverflow.com/a/37733801).

$arr = 1..5
$first, $rest= $arr

$rest
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

十多年来,它一直是Powershell的一个特色.我从这篇博客文章中找到了这个功能:https://blogs.msdn.microsoft.com/powershell/2007/02/05/powershell-tip-how-to-shift-arrays/

  • 如果您希望“$rest”具有一致的数据类型,则此方法不可靠。如果 `$arr` 只有 2 个元素,则 `$rest` 将是标量,否则为数组甚至 null (2认同)
  • 除非 `$rest` 已经是数组类型,在这种情况下它将仍然是数组类型。所以 `$first,$arr = $arr` 应该可以正常工作。您还可以通过以下方式强制解决问题:`$first,[object[]]$rest = $arr` (2认同)

Slo*_*ire 12

这将允许您从数组中删除每个出现的任意元素,而无需使用更复杂的.NET对象.

$x=<array element to remove>
$test = $test | Where-Object { $_ -ne $test[$x] }
Run Code Online (Sandbox Code Playgroud)

这将做同样的事情,但只会删除其中一个元素.如果有重复,它们将保留.

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


Ron*_*eil 9

您可以使用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:\>
Run Code Online (Sandbox Code Playgroud)

  • @ZéCláudio Powershell 的默认行为是将单项序列展平为标量,将空序列展平为“$null”。要在所有情况下强制使用数组,请将序列包装在 [@(...) 数组子表达式运算符](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about /about_operators?view=powershell-6#array-subexpression-operator--)。 (4认同)

Red*_*ddy 5

只是更新 - @Frode F. 答案有问题

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

$arr = $arr[1..($arr.Length-1)]
Run Code Online (Sandbox Code Playgroud)

如果元素数量为 1,则不会删除该元素

if($arr.Length -le 1) {
    $arr = @()
}
else {
    $arr = $arr[1..($arr.length - 1)]
}
Run Code Online (Sandbox Code Playgroud)