我正在寻找一种更好的模式,用于处理每个元素的列表,然后根据结果从列表中删除。
你不能在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的当前位置。
有没有一种优雅的方式来做到这一点?
当前回答
我希望“模式”是这样的:
foreach( thing in thingpile )
{
if( /* condition#1 */ )
{
foreach.markfordeleting( thing );
}
elseif( /* condition#2 */ )
{
foreach.markforkeeping( thing );
}
}
foreachcompleted
{
// then the programmer's choices would be:
// delete everything that was marked for deleting
foreach.deletenow(thingpile);
// ...or... keep only things that were marked for keeping
foreach.keepnow(thingpile);
// ...or even... make a new list of the unmarked items
others = foreach.unmarked(thingpile);
}
这将使代码与程序员大脑中进行的过程保持一致。
其他回答
复制您正在迭代的列表。然后从副本中删除并与原件相互作用。倒退是令人困惑的,并且在并行循环时不能很好地工作。
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
使用.ToList()将创建一个列表的副本,正如这个问题中所解释的: ToList()—它是否创建一个新列表?
通过使用ToList(),可以从原始列表中删除,因为实际上是在迭代一个副本。
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
在泛型列表上使用ToArray()可以在泛型列表上执行Remove(item):
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
foreach (var item in list.ToList()) {
list.Remove(item);
}
如果你将".ToList()"添加到列表(或LINQ查询的结果)中,你可以直接从"list"中删除"item",而不用担心"Collection was modified;枚举操作不能执行"错误。编译器会复制“list”,这样你就可以安全地删除数组了。
虽然这种模式不是超级高效,但它有一种自然的感觉,并且对于几乎任何情况都足够灵活。例如,当您想要将每个“项”保存到一个DB,并仅当DB保存成功时才将其从列表中删除。
你不能使用foreach,但是当你删除一个项目时,你可以向前迭代并管理你的循环索引变量,如下所示:
for (int i = 0; i < elements.Count; i++)
{
if (<condition>)
{
// Decrement the loop counter to iterate this index again, since later elements will get moved down during the remove operation.
elements.RemoveAt(i--);
}
}
注意,一般来说,所有这些技术都依赖于被迭代的集合的行为。这里显示的技术将与标准List(T)一起工作。(很有可能编写自己的集合类和迭代器,允许在foreach循环期间删除项。)