How to remove elements from a generic list while iterating over it?

前端 未结 27 2375
忘了有多久
忘了有多久 2020-11-21 22:48

I am looking for a better pattern for working with a list of elements which each need processed and then depending on the outcome are removed from

相关标签:
27条回答
  • 2020-11-21 23:15

    The best way to remove items from a list while iterating over it is to use RemoveAll(). But the main concern written by people is that they have to do some complex things inside the loop and/or have complex compare cases.

    The solution is to still use RemoveAll() but use this notation:

    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;
    });
    
    0 讨论(0)
  • 2020-11-21 23:15
    myList.RemoveAt(i--);
    
    simples;
    
    0 讨论(0)
  • 2020-11-21 23:16
     foreach (var item in list.ToList()) {
         list.Remove(item);
     }
    

    If you add ".ToList()" to your list (or the results of a LINQ query), you can remove "item" directly from "list" without the dreaded "Collection was modified; enumeration operation may not execute." error. The compiler makes a copy of "list", so that you can safely do the remove on the array.

    While this pattern is not super efficient, it has a natural feel and is flexible enough for almost any situation. Such as when you want to save each "item" to a DB and remove it from the list only when the DB save succeeds.

    0 讨论(0)
  • 2020-11-21 23:18

    I would do like this

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

    OUTPUT

    Fred Jones
    Billy TheKid
    
    0 讨论(0)
  • 2020-11-21 23:20

    You can't use foreach, but you could iterate forwards and manage your loop index variable when you remove an item, like so:

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

    Note that in general all of these techniques rely on the behaviour of the collection being iterated. The technique shown here will work with the standard List(T). (It is quite possible to write your own collection class and iterator that does allow item removal during a foreach loop.)

    0 讨论(0)
  • 2020-11-21 23:20
    foreach(var item in list.ToList())
    
    {
    
    if(item.Delete) list.Remove(item);
    
    }
    

    Simply create an entirely new list from the first one. I say "Easy" rather than "Right" as creating an entirely new list probably comes at a performance premium over the previous method (I haven't bothered with any benchmarking.) I generally prefer this pattern, it can also be useful in overcoming Linq-To-Entities limitations.

    for(i = list.Count()-1;i>=0;i--)
    
    {
    
    item=list[i];
    
    if (item.Delete) list.Remove(item);
    
    }
    

    This way cycles through the list backwards with a plain old For loop. Doing this forwards could be problematic if the size of the collection changes, but backwards should always be safe.

    0 讨论(0)
提交回复
热议问题