Intelligent way of removing items from a List while enumerating in C#

后端 未结 10 474
闹比i
闹比i 2020-11-29 19:05

I have the classic case of trying to remove an item from a collection while enumerating it in a loop:

List myIntCollection = new List()         


        
相关标签:
10条回答
  • 2020-11-29 19:42

    For those it may help, I wrote this Extension method to remove items matching the predicate and return the list of removed items.

        public static IList<T> RemoveAllKeepRemoved<T>(this IList<T> source, Predicate<T> predicate)
        {
            IList<T> removed = new List<T>();
            for (int i = source.Count - 1; i >= 0; i--)
            {
                T item = source[i];
                if (predicate(item))
                {
                    removed.Add(item);
                    source.RemoveAt(i);
                }
            }
            return removed;
        }
    
    0 讨论(0)
  • 2020-11-29 19:45

    Let's add you code:

    List<int> myIntCollection=new List<int>();
    myIntCollection.Add(42);
    myIntCollection.Add(12);
    myIntCollection.Add(96);
    myIntCollection.Add(25);
    

    If you want to change the list while you're in a foreach, you must type .ToList()

    foreach(int i in myIntCollection.ToList())
    {
        if (i == 42)
           myIntCollection.Remove(96);
        if (i == 25)
           myIntCollection.Remove(42);
    }
    
    0 讨论(0)
  • 2020-11-29 19:49

    I know this post is old, but I thought I'd share what worked for me.

    Create a copy of the list for enumerating, and then in the for each loop, you can process on the copied values, and remove/add/whatever with the source list.

    private void ProcessAndRemove(IList<Item> list)
    {
        foreach (var item in list.ToList())
        {
            if (item.DeterminingFactor > 10)
            {
                list.Remove(item);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:51

    If you must both enumerate a List<T> and remove from it then I suggest simply using a while loop instead of a foreach

    var index = 0;
    while (index < myList.Count) {
      if (someCondition(myList[index])) {
        myList.RemoveAt(index);
      } else {
        index++;
      }
    }
    
    0 讨论(0)
  • 2020-11-29 19:59

    When you need to iterate through a list and might modify it during the loop then you are better off using a for loop:

    for (int i = 0; i < myIntCollection.Count; i++)
    {
        if (myIntCollection[i] == 42)
        {
            myIntCollection.Remove(i);
            i--;
        }
    }
    

    Of course you must be careful, for example I decrement i whenever an item is removed as otherwise we will skip entries (an alternative is to go backwards though the list).

    If you have Linq then you should just use RemoveAll as dlev has suggested.

    0 讨论(0)
  • 2020-11-29 19:59

    As you enumerate the list, add the one you want to KEEP to a new list. Afterward, assign the new list to the myIntCollection

    List<int> myIntCollection=new List<int>();
    myIntCollection.Add(42);
    List<int> newCollection=new List<int>(myIntCollection.Count);
    
    foreach(int i in myIntCollection)
    {
        if (i want to delete this)
            ///
        else
            newCollection.Add(i);
    }
    myIntCollection = newCollection;
    
    0 讨论(0)
提交回复
热议问题