我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。
你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。
有没有一种优雅的方式来做到这一点?
我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。
你不能在foreach (var element in X)中使用.Remove(element)(因为它会导致Collection被修改;枚举操作可能无法执行。例外)……你也不能使用for (int I = 0;i < elements.Count();i++)和. removeat (i),因为它破坏了你在集合中相对于i的当前位置。
有没有一种优雅的方式来做到这一点?
当前回答
选择您确实需要的元素,而不是试图删除您不想要的元素。这比删除元素要容易得多(通常也更有效)。
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
我想把这篇评论作为对Michael Dillon下面评论的回应,但它太长了,可能在我的回答中有用:
就我个人而言,我从来不会一个接一个地删除项,如果你确实需要删除,那么调用RemoveAll,它接受一个谓词,只重新排列一次内部数组,而remove则是一个数组。为您删除的每个元素复制操作。RemoveAll大大提高了效率。
当你在一个列表上向后迭代时,你已经有了你想要删除的元素的索引,所以调用RemoveAt会更有效,因为remove首先遍历列表来找到你想要删除的元素的索引,但你已经知道那个索引。
总而言之,我不认为有任何理由在for循环中调用Remove。理想情况下,如果可能的话,使用上面的代码根据需要从列表中输入元素,这样就根本不需要创建第二个数据结构。
其他回答
选择您确实需要的元素,而不是试图删除您不想要的元素。这比删除元素要容易得多(通常也更有效)。
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
我想把这篇评论作为对Michael Dillon下面评论的回应,但它太长了,可能在我的回答中有用:
就我个人而言,我从来不会一个接一个地删除项,如果你确实需要删除,那么调用RemoveAll,它接受一个谓词,只重新排列一次内部数组,而remove则是一个数组。为您删除的每个元素复制操作。RemoveAll大大提高了效率。
当你在一个列表上向后迭代时,你已经有了你想要删除的元素的索引,所以调用RemoveAt会更有效,因为remove首先遍历列表来找到你想要删除的元素的索引,但你已经知道那个索引。
总而言之,我不认为有任何理由在for循环中调用Remove。理想情况下,如果可能的话,使用上面的代码根据需要从列表中输入元素,这样就根本不需要创建第二个数据结构。
如果决定删除哪些项的函数没有副作用,也没有改变项(这是一个纯函数),一个简单有效的(线性时间)解决方案是:
list.RemoveAll(condition);
如果有副作用,我会使用如下方法:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
这仍然是线性时间,假设哈希是好的。但是由于hashset,它增加了内存使用。
最后,如果你的列表只是一个IList<T>,而不是一个list <T>,我建议我的答案,我怎么能做这个特殊的foreach迭代器?与许多其他答案的二次运行时相比,给出IList<T>的典型实现,它将具有线性运行时。
复制您正在迭代的列表。然后从副本中删除并与原件相互作用。倒退是令人困惑的,并且在并行循环时不能很好地工作。
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
我将从一个过滤掉您不想保留的元素的LINQ查询中重新分配列表。
list = list.Where(item => ...).ToList();
除非列表非常大,否则这样做应该不会有明显的性能问题。
从列表中删除一个项的成本与后面要删除的项的数量成正比。在前半部分的条目符合删除条件的情况下,任何基于单独删除条目的方法最终都将不得不执行大约N*N/4个条目复制操作,如果列表很大,这可能会非常昂贵。
A faster approach is to scan through the list to find the first item to be removed (if any), and then from that point forward copy each item which should be retained to the spot where it belongs. Once this is done, if R items should be retained, the first R items in the list will be those R items, and all of the items requiring deletion will be at the end. If those items are deleted in reverse order, the system won't end up having to copy any of them, so if the list had N items of which R items, including all of the first F, were retained, it will be necessary to copy R-F items, and shrink the list by one item N-R times. All linear time.