PowerShell从数组中删除项[0]

时间:2014-07-15 09:41:16

标签: arrays powershell arraylist

我正在努力消除数组的第一行(项目ID)。

$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

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

这两种类型的专业和缺点是什么?谢谢你的帮助。

11 个答案:

答案 0 :(得分:19)

数组是固定大小的,就像错误所说的那样。 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

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

答案 1 :(得分:10)

这将允许您从数组中删除每个出现的任意元素,而无需使用更复杂的.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 { $_ } }

答案 2 :(得分:8)

另一种选择是使用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

十多年来,它一直是Powershell的功能。我从以下博客文章中发现了此功能:https://blogs.msdn.microsoft.com/powershell/2007/02/05/powershell-tip-how-to-shift-arrays/

答案 3 :(得分:7)

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

答案 4 :(得分:3)

只是为了更新 - @Frode F. answer

存在问题
  

如果数组中的元素数量超过1

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

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

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

答案 5 :(得分:2)

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

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

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

答案 6 :(得分:0)

原谅迟到的回答,但我也在努力解决这个问题。为了我的意图和目的(写入文本文件),我意识到由于数组是固定大小 - 而不是删除它我可以将值设置为string.empty。

{{1}}

对我来说,这摆脱了我在平面文件中不想要的标题。希望这有助于其他人。

答案 7 :(得分:0)

如果我们遇到必须由某些部分执行大数组(或ArrayList)的情况 - 我使用了一些生活方式:

#$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项)

答案 8 :(得分:0)

removeat()可用于数组列表(例如$ error):

[collections.arraylist]$a = get-process
$a.removeat(0)

答案 9 :(得分:0)

将其他答案与我的小改动相结合(将其用作 $profile 中的全局函数):

function global:sudo {
    $runArgs = $args

    if($runArgs.Length -le 1) {
        $runArgs = ""
    }
    else {
        $runArgs = $runArgs[1..($runArgs.length - 1)]
        $runArgs = $runArgs -join " "
    }
    
    Start-Process $args[0] -ArgumentList $runArgs -Verb runas    
}

所以,sudo notepadsudo notepad c:\windows\abc.txt 都可以工作,并且应该优雅地传递参数(虽然没有真正彻底检查)

答案 10 :(得分:0)

如果要删除已知索引 x(基数为 0)的一行,也可以只复制数组的下部和上部。

从arry中删除第x行

$LastElement = $arry.GetUpperBound(0)

if ($LastElement -ge 0) {

    if ($x -eq 0) {
        $lowerRange = @()
    } else {
        $lowerRange = @($arry[0..($x-1)])
    }

    if ($x -eq $LastElement) {
        $upperRange = @()
    } else {
        $upperRange = @($arry[($x+1)..$LastElement])
    }

    $arry = @($lowerRange; $upperRange)
}