这里有两个选项。最容易编码但效果最差的选项是,只需获取所有要删除的项目,然后在找到它们后全部删除:
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)操作。即使列表不是巨大的,但这仍然是一个问题,尤其是在处理非微不足道的大小时。
相反,我们只需要遍历集合,而不使用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")