我经常需要根据某些条件从一个集合中删除一些对象,每次我都用它来删除:
Get-SomeCollection | ? { $_.SomeProperty -eq "SomeValue" } | % { $_.Delete() }
但是这将只删除第一个元素,然后抛出异常“Collection was modified ... bla bla ...”。我明白了这一点,但这样做的推荐方法是什么?
我通常使用一些数组itemsToDelete
,然后我再次遍历该数组并执行删除操作:
$itemsToDelete = @()
Get-SomeCollection | ? { $_.SomeProperty -eq "SomeValue" } | % { $itemsToDelete += $_ }
$itemsToDelete | % { $_.Delete() }
我想知道这是足够好还是更好的方式。
答案 0 :(得分:4)
您通常会使用过滤器来实际过滤项目。因此,您不要修改原始集合,而只是过滤掉您感兴趣的集合。
Get-SomeCollection | ? { $_.SomeProperty -ne "SomeValue" }
如果您需要对要删除的项目调用操作,则只需创建已过滤集合的副本并枚举该过滤集合即可。这样做非常简单,因为您只需要将表达式括在parantheses中,以便在使用以下命令运行枚举之前对其进行求值:
(Get-SomeCollection | ? { $_.SomeProperty -eq "SomeValue" }) | % { $_.Delete() }
答案 1 :(得分:0)
我不确定powershell的语法,但.NET中的简单foreach语句存在此问题
解决方案是在for循环中向后迭代。
而不是:
foreach(var item in collection)
{
if(condition)
{
collection.Remove(item); //exception!
}
}
你这样做:
for(int count = collection.Count - 1; count > 0; count--)
{
var currentItem = collection[count];
if(condition)
{
collection.RemoveAt(count);
}
}