簡體   English   中英

PowerShell 從數組中刪除項目 [0]

[英]PowerShell Remove item [0] from an array

我很難刪除數組的第一行(項目 ID)。

$test.GetType()

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

要列出我嘗試過的所有選項,$test | gm ,$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) 將腳本開頭的所有 arrays 聲明為列表是最佳做法嗎? 還是稍后在需要此功能時將帶有$collection = ({$test}.Invoke())的 arrays 轉換為列表更好?

兩種類型的優缺點是什么? 謝謝您的幫助。

另一種選擇是使用 Powershell 分配多個變量的能力(請參閱其他答案)。

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

$rest
2
3
4
5

十多年來,它一直是 Powershell 的一個功能。 我從MSDN 博客文章中發現了此功能:

數組是固定大小的,就像錯誤所說的那樣。 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 答案about_Arrays

這將允許您從數組中刪除每個出現的任意元素,而無需求助於更復雜的 .NET 對象。

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

或者,

$x=<array index 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 { $_ } }

同樣基於其中一條評論,如果您不確定$test是一個數組,那么將$test=@($test)放在首位可能是明智的。

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

只是為了更新 - @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)]

如果您要重復執行此操作,則應從數組列表或泛型集合開始。 如果它是一個大數組,您可能只想將創建它的表達式放入腳本塊中並對其執行 .invoke(),而不是讓管道創建一個數組,然后將其轉換為集合。

removeat() 適用於數組列表(如 $error):

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

有一種更簡單優雅的方法可以做到這一點。 該答案也適用於具有單個元素的 arrays(與之前給出的其他一些答案不同)。 它也適用於任何所需的索引。

$arr = @(1,2,3)
$arr -ne $arr[0] #remove first element: @(2,3)
$arr -ne $arr[1] #remove second element: @(1,3)
$arr -ne $arr[-1] #remove last element: @(1,2)

請原諒我遲到的答案,但我也在為此苦苦掙扎。 出於我的意圖和目的(寫入文本文件),我意識到由於數組是固定大小——而不是刪除它,我可以將值設置為 string.empty。

$results = SQLQuery -connectionString $connectionString  -query $query;
$results[0] = '';
foreach ($r in $results) {
    Add-Content $skus $r[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 個項目)處理大數組

將其他答案與我的小改動相結合(將其用作 $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都可以使用,並且應該優雅地傳遞參數(雖然沒有真正徹底檢查)

如果要刪除已知索引 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)
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM