Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在遍历泛型列表时从该列表中删除元素?_C#_List_Loops_Generics_Key Value - Fatal编程技术网

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;
        }
    }
}