[英]Remove a row from a powershell array/collection/hashtable
我有一個大型數組(從Excel電子表格導入),它有一個我要刪除的“總”行。 它始終是數組中的最后一項。 我試圖找到一種方法來刪除最后一個數組項,但不能。 以下數據和代碼示例:
$data = Import-XLSX -Path "C:\Pathtofile\spreadsheet.xlsx" -Sheet "SheetName" -RowStart 3
$data | ? {$_.Server -eq "Total"}
Server : Total
VLAN :
IP Address :
CPU : 84
RAM : 313
C:\ : 2840
D:\ : 17950
OS Version :
OS Edition :
SQL Version :
SQL Edition :
Datastore :
Reboot :
Notes :
我希望能夠從數組中刪除此行。 我嘗試過以下方法:
$data.Remove("Total")
Exception calling "Remove" with "1" argument(s): "Collection was of a fixed size."
At line:1 char:1
+ $ImportCSV.Remove("Total")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
如果我檢查數組類型,我得到以下內容:
$data.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
如果我像這樣重新鍵入對象,我得到以下內容:
$data = {$data}.Invoke()
$data.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Collection`1 System.Object
$data.Remove("Total")
False
這不會刪除該項目。 我在這里錯過了什么?
數組在PowerShell中是不可變的,您無法添加或刪除它們中的元素。 你能做的是:
a)創建一個新數組並過濾掉你不想要的數組(例如使用-ne
):
$data = $data | ? {$_.Server -ne "Total"}
要么
b)按索引選擇最后一個元素的所有內容(可能是大數據庫上的資源,我不知道):
$data = $data[0..($data.Count-2)]
要么
c)將其轉換為[System.Collections.ArrayList]
,這是可變的,然后從中刪除一個元素:
$data = [System.Collections.ArrayList]$data
$data.RemoveAt($data.Count-1)
通過分析和背景信息補充TessellatingHeckler的有用答案 :
如上所述, PowerShell數組(.NET類型[System.Object[]]
)是固定大小的 - 您無法添加或刪除元素 (但是,您可以更改現有元素的值 )。
當您使用+
或+=
將元素“添加”到PowerShell數組時,會在后台創建一個新數組,這是原始數據的副本 (淺層克隆)。
唯一的原因陣列具有.Add()
.Remove()
和.RemoveAt()
方法是他們實現通用System.Collections.IList
接口 ,它是由許多不同類型的集合,其中有一些是實施調整大小。
試圖在固定大小的集合(如數組)上調用這些方法會導致"Collection was of a fixed size."
你看到的錯誤信息。
無論輸入集合的類型如何, 通過輸出多個對象的管道發送任何內容都將作為(新) 數組出現 。 (單個結果對象作為自身輸出,不包含在集合中。)
$data | ? {$_.Server -ne "Total"}
等命令過濾掉集合的元素 $data | ? {$_.Server -ne "Total"}
$data | ? {$_.Server -ne "Total"}
創建一個總是數組的新集合( [System.Object[]]
,如果有超過1個輸出對象)。 為什么嘗試失敗 :
$data.Remove("Total")
從根本上失敗了,因為數組不支持刪除,如上所述。
但即使$data
是可調整大小的集合(例如[System.Collections.ArrayList]
),傳遞"Total"
也不會有效,因為您嘗試調用的IList.Remove
方法要求您傳遞元素以移除自身在你的情況下,它將是.Server
屬性包含"Total"
的對象 ,最容易作為$data[-1]
訪問。
另請注意,傳遞不是列表元素的值是安靜的無操作(如果集合可調整大小)。
鑒於您想要刪除最后一個元素,基於索引的IList.RemoveAt
方法將是更簡單的選擇。
{$data}.Invoke()
確實執行了{$data}.Invoke()
的重新輸入 ,但是以最神秘的方式避免 :
乍一看, 從概念上講 ,該命令應該是一個無操作 :你只是在一個腳本塊 ( { ... }
)中包含一個變量引用,然后你可以調用它,它應該只輸出變量的值 。
它不是無操作的原因是 你繞過PowerShell對腳本塊的正常處理是通過.NET .Invoke()
方法調用它而不是通常調用腳本塊的方式:使用call operator &
。
如果在腳本塊上使用.Invoke()
,則始終會獲得[System.Collections.ObjectModel.Collection[psobject]]
實例(即使它只包含1個對象)。
相比之下,在幕后調用.Invoke()
之后使用&
執行額外的工作:如果集合只包含1個元素,則直接返回該元素(集合被解包)。 否則,集合將轉換為PowerShell數組( [System.Object[]]
;我不清楚此轉換的具體情況)。
既然你使用.Invoke()
直接,你要調用.Remove()
上運行[System.Collections.ObjectModel.Collection[psobject]]
這是可調整大小,並有自己的.Remove()
方法,其排除邏輯是一樣的就像IList.Remove()
,它會影響它。
但是,它與IList.Remove()
不同之處在於返回反映刪除嘗試成功的[bool]
,這就是為什么你在第二次嘗試時得到false
原因。
然而,與第一次嘗試不同的是,這次失敗不是基本的,並且傳入最后一個元素所包含的對象 (行); 類似地,具有最高索引的.RemoveAt()
可以工作:
# Convert to [System.Collections.ObjectModel.Collection[psobject]]
$dataResizable = { $data }.Invoke()
# Remove last item by index.
$dataResizable.RemoveAt($dataResizable.Count-1)
# Alternative: Remove last item by object reference / value.
# Returns [bool], which we suppress.
$null = $dataResizable.Remove($dataResizable[-1])
所有這一切, 在腳本塊上使用.Invoke()
只是為了得到一個可調整大小的集合是不明智的 。
相反,選擇TessellatingHeckler的答案中演示的方法之一。
此外, PSv5 +提供了一種從通過管道傳遞的集合中刪除最后一個元素的簡單方法, Select-Object -SkipLast 1
:
$data = Import-XLSX -Path "C:\Pathtofile\spreadsheet.xlsx" -Sheet "SheetName" -RowStart 3 |
Select-Object -SkipLast 1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.