C# 如何在遍历泛型列表时从该列表中删除元素?
我正在寻找一种更好的模式,用于处理每个需要处理的元素列表,然后根据结果从列表中删除这些元素 您不能在C# 如何在遍历泛型列表时从该列表中删除元素?,c#,list,loops,generics,key-value,C#,List,Loops,Generics,Key Value,我正在寻找一种更好的模式,用于处理每个需要处理的元素列表,然后根据结果从列表中删除这些元素 您不能在foreach(X中的var元素)中使用.Remove(element)(因为它导致集合被修改;枚举操作可能无法执行。异常)。。。您也不能使用for(int i=0;iConsole.WriteLine(i)); list.RemoveAll(i=>i>5); 控制台。WriteLine(“在:”)之后; list.ForEach(i=>Console.WriteLine(i)); 在通用列表中使
foreach(X中的var元素)中使用.Remove(element)
(因为它导致集合被修改;枚举操作可能无法执行。
异常)。。。您也不能使用for(int i=0;i
和.RemoveAt(i)
,因为它会破坏您在集合中相对于i
的当前位置
有没有一种优雅的方法可以做到这一点?我会从LINQ查询中重新分配列表,该查询过滤掉了您不想保留的元素
list = list.Where(item => ...).ToList();
除非列表非常大,否则在执行此操作时不会出现明显的性能问题。一个简单明了的解决方案:
使用标准for循环在集合上向后运行,RemoveAt(i)
删除元素。使用for循环反向迭代列表:
for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}
例如:
var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
下面是一个简单的示例来演示:
var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
var list=新列表(可枚举范围(1,10));
Console.WriteLine(“之前:”);
list.ForEach(i=>Console.WriteLine(i));
list.RemoveAll(i=>i>5);
控制台。WriteLine(“在:”)之后;
list.ForEach(i=>Console.WriteLine(i));
在通用列表中使用ToArray()可以删除通用列表中的(项目):
List<String> strings = new List<string>() { "a", "b", "c", "d" };
foreach (string s in strings.ToArray())
{
if (s == "b")
strings.Remove(s);
}
List strings=newlist(){“a”、“b”、“c”、“d”};
foreach(strings.ToArray()中的字符串s)
{
如果(s==“b”)
字符串。删除(s);
}
选择您想要的元素,而不是尝试删除您不想要的元素。这比删除元素容易得多(通常也更有效)
var newSequence = (from el in list
where el.Something || el.AnotherThing < 0
select el);
var newSequence=(来自列表中的el)
其中el.某物| el.另一物<0
选择el);
我想把这篇文章作为对迈克尔·狄龙(Michael Dillon)在下面留下的评论的回应,但这篇文章太长了,而且可能对我的回答很有用:
就我个人而言,我永远不会逐个删除项,如果确实需要删除,则调用RemoveAll
,它接受谓词并只重新排列内部数组一次,而remove
对删除的每个元素执行数组。复制操作RemoveAll
的效率要高得多
当你向后迭代一个列表时,你已经有了你想要删除的元素的索引,所以调用RemoveAt
会更有效,因为remove
首先遍历列表,找到你想要删除的元素的索引,但是你已经知道了这个索引
总之,我不认为有任何理由在for循环中调用Remove
。理想情况下,如果可能的话,使用上面的代码根据需要从列表中流式传输元素,这样就不需要创建第二个数据结构 当您要在迭代集合时从集合中删除元素时,应该首先想到反向迭代
幸运的是,有一个比编写for循环更优雅的解决方案,因为for循环需要不必要的键入,并且容易出错
ICollection<int> test = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
foreach (int myInt in test.Reverse<int>())
{
if (myInt % 2 == 0)
{
test.Remove(myInt);
}
}
ICollection test=新列表(新int[]{1,2,3,4,5,6,7,8,9,10});
foreach(test.Reverse()中的int-myInt)
{
如果(myInt%2==0)
{
测试。移除(myInt);
}
}
列表列表=新列表();
FindAll(element=>element.confidents(Condition)).ForEach(element=>TheList.Remove(element));
使用.ToList()将复制您的列表,如本问题所述:
通过使用ToList(),您可以从原始列表中删除,因为您实际上是在对副本进行迭代
foreach (var item in listTracked.ToList()) {
if (DetermineIfRequiresRemoval(item)) {
listTracked.Remove(item)
}
}
我发现自己处于一种类似的情况,我必须删除给定列表中的每一个第n个元素
for(int i=0,j=0,n=3;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 messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
这将使代码与程序员大脑中进行的过程保持一致。假设谓词是元素的布尔属性,如果为真,则应删除该元素:
int i = 0;
while (i < list.Count())
{
if (list[i].predicate == true)
{
list.RemoveAt(i);
continue;
}
i++;
}
inti=0;
而(i
因为任何移除都是在您可以使用的条件下进行的
list.RemoveAll(item => item.Value == someValue);
如果确定要删除哪些项的函数没有副作用,并且没有对该项进行变异(这是一个纯函数),则简单有效的(线性时间)解决方案是:
list.RemoveAll(condition);
如果有副作用,我会使用类似的方法:
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
var toRemove=newhashset();
foreach(项目中的var项目)
{
...
如果(条件)
删除。添加(项目);
}
items.RemoveAll(toRemove.Contains);
假设散列是好的,这仍然是线性时间。但是由于hashset,它的内存使用量增加了
最后,如果您的列表只是一个IList
而不是list
,我建议您回答这个问题。与许多其他答案的二次运行时相比,对于IList的典型实现,这将具有线性运行时
foreach (var item in list.ToList()) {
list.Remove(item);
}
如果将“.ToList()”添加到列表(或LINQ查询的结果)中,则可以直接从“列表”中删除“项”,而无需可怕的“集合已修改;枚举”
var toRemove = new HashSet<T>();
foreach(var item in items)
{
...
if(condition)
toRemove.Add(item);
}
items.RemoveAll(toRemove.Contains);
foreach (var item in list.ToList()) {
list.Remove(item);
}
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--);
}
}
myList.RemoveAt(i--);
simples;
// Create a list to be filtered
IList<int> elements = new List<int>(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
// Filter the list
int kept = 0;
for (int i = 0; i < elements.Count; i++) {
// Test whether this is an element that we want to keep.
if (elements[i] % 3 > 0) {
// Add it to the list of kept elements.
elements[kept] = elements[i];
kept++;
}
}
// Unfortunately IList has no Resize method. So instead we
// remove the last element of the list until: elements.Count == kept.
while (kept < elements.Count) elements.RemoveAt(elements.Count-1);
var messageList = ...;
// Restrict your list to certain criteria
var customMessageList = messageList.FindAll(m => m.UserId == someId);
if (customMessageList != null && customMessageList.Count > 0)
{
// Create list with positions in origin list
List<int> positionList = new List<int>();
foreach (var message in customMessageList)
{
var position = messageList.FindIndex(m => m.MessageId == message.MessageId);
if (position != -1)
positionList.Add(position);
}
// To be able to remove the items in the origin list, we do it backwards
// so that the order of indices stays the same
positionList = positionList.OrderByDescending(p => p).ToList();
foreach (var position in positionList)
{
messageList.RemoveAt(position);
}
}
var ids = new List<int> { 1, 2, 3, 4 };
var iterableIds = ids.ToList();
Parallel.ForEach(iterableIds, id =>
{
ids.Remove(id);
});
var list = new List<int>(Enumerable.Range(1, 10));
list.RemoveAll(item =>
{
// Do some complex operations here
// Or even some operations on the items
SomeFunction(item);
// In the end return true if the item is to be removed. False otherwise
return item > 5;
});
foreach(var item in list.ToList())
{
if(item.Delete) list.Remove(item);
}
for(i = list.Count()-1;i>=0;i--)
{
item=list[i];
if (item.Delete) list.Remove(item);
}
foreach(var item in list.ToList()){if(item.Delete) list.Remove(item);}
list.RemoveAll(p=>p.Delete);
using System.Linq;
List<MyProperty> _Group = new List<MyProperty>();
// ... add elements
bool cond = true;
foreach (MyProperty currObj in _Group)
{
if (cond)
{
// SET - element can be deleted
currObj.REMOVE_ME = true;
}
}
// RESET
_Group.RemoveAll(r => r.REMOVE_ME);
ArrayList place_holder = new ArrayList();
place_holder.Add("1");
place_holder.Add("2");
place_holder.Add("3");
place_holder.Add("4");
for(int i = place_holder.Count-1; i>= 0; i--){
if(i>= place_holder.Count){
i = place_holder.Count-1;
}
// some method that removes multiple elements here
}
using System.IO;
using System;
using System.Collections.Generic;
class Author
{
public string Firstname;
public string Lastname;
public int no;
}
class Program
{
private static bool isEven(int i)
{
return ((i % 2) == 0);
}
static void Main()
{
var authorsList = new List<Author>()
{
new Author{ Firstname = "Bob", Lastname = "Smith", no = 2 },
new Author{ Firstname = "Fred", Lastname = "Jones", no = 3 },
new Author{ Firstname = "Brian", Lastname = "Brains", no = 4 },
new Author{ Firstname = "Billy", Lastname = "TheKid", no = 1 }
};
authorsList.RemoveAll(item => isEven(item.no));
foreach(var auth in authorsList)
{
Console.WriteLine(auth.Firstname + " " + auth.Lastname);
}
}
}
Fred Jones
Billy TheKid
var numbers = new List<int>(Enumerable.Range(1, 3));
while (numbers.Count > 0)
{
numbers.RemoveAt(0);
}
var numbers = new List<int>(Enumerable.Range(1, 3));
for (; numbers.Count > 0;)
{
numbers.RemoveAt(0);
}
public static class Extensions
{
public static IList<T> Remove<T>(
this IList<T> numbers,
Func<T, bool> predicate)
{
numbers.ForEachBackwards(predicate, (n, index) => numbers.RemoveAt(index));
return numbers;
}
public static void ForEachBackwards<T>(
this IList<T> numbers,
Func<T, bool> predicate,
Action<T, int> action)
{
for (var i = numbers.Count - 1; i >= 0; i--)
{
if (predicate(numbers[i]))
{
action(numbers[i], i);
}
}
}
}
var numbers = new List<int>(Enumerable.Range(1, 10)).Remove((n) => n > 5);
foreach (var elem in list.AsReverse())
{
//Do stuff with elem
//list.Remove(elem); //Delete it if you want
}
public static class ReverseListExtension
{
public static ReverseList<T> AsReverse<T>(this List<T> list) => new ReverseList<T>(list);
public class ReverseList<T> : IEnumerable
{
List<T> list;
public ReverseList(List<T> list){ this.list = list; }
public IEnumerator GetEnumerator()
{
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
yield break;
}
}
}