所以这里有两个选择。最容易编码但效率最低的选项是抓住所有要删除的项目,然后在找到它们后将它们全部删除:
var carsToRemove = carList.Where(carNode => carNode.paint.color == "blue")
.ToList();
foreach(var car in carsToRemove)
carList.Remove(car);
请注意,ToList
这里的调用非常重要;根本Where
不允许推迟底层列表的迭代,否则你会得到相同的并发修改错误。
这里有两个问题。首先,您需要将所有要删除的项目保存在内存中。还不错,除非你有很多(我的意思是很多)。更大的问题是你没有节点对象,你有节点的值,所以你需要从头开始遍历整个列表来找到每个对象并删除它们。您已将 O(n) 操作转换为 O(n^2) 操作。即使列表不是巨大的,但只是大小不一,这也是一个问题。
相反,我们只需要在不使用 a 的情况下遍历集合,foreach
以便我们拥有对Node
对象的引用,并且通过正确管理何时/如何遍历和修改集合,我们不会获得并发修改异常。
var currentNode = list.First;
while (currentNode != null)
{
if (currentNode.Value.color == "blue")
{
var toRemove = currentNode;
currentNode = currentNode.Next;
list.Remove(toRemove);
}
else
{
currentNode = currentNode.Next;
}
}
它不是那么漂亮,但它会更有效率。
现在,理想情况下LinkedList
会有一种RemoveAll
方法,这样您就不必一直为此烦恼。可悲的是,它没有。不过,从好的方面来说,您可以添加自己的扩展方法:
public static void RemoveAll<T>(this LinkedList<T> list, Func<T, bool> predicate)
{
var currentNode = list.First;
while (currentNode != null)
{
if (predicate(currentNode.Value))
{
var toRemove = currentNode;
currentNode = currentNode.Next;
list.Remove(toRemove);
}
else
{
currentNode = currentNode.Next;
}
}
}
现在我们可以写:
carList.RemoveAll(car => car.paint.color == "blue");