0

I am curious as to what is the best way to modify a list in c#. As far as I'm aware, the foreach loop is used to iterate over the list to get the desired information and if you need to modify the list then use a for loop. I have found 3 ways to modify a list but they all seem to pretty much remove the items as intended.

So my questions are:

1) What is the difference between these 3 ways shown below?

2) is there a specific time where one of them should be used over the other way?

3) Is there any other better ways to modify a list?

4) When removing you are meant to reverse the list, is this simply to not mess up the order and cause unpredictable side effects?

Reverse for loop:

List<int> integerListForReverse = new List<int>();
for(int i = 0; i <10; i ++)
{
    integerListForReverse.Add(i);
}

for (int i = integerListForReverse.Count - 1; i >= 0; i--)
{
    int ints = i;
    if(ints % 2 == 0)
    {
        integerListForReverse.Remove(ints);
        Console.WriteLine(ints + " reverse for loop");
    }
}

Create a copy of the list

List<int> integerListForeachCopy = new List<int>();
for (int i = 0; i < 10; i++)
{
    integerListForeachCopy.Add(i);
}

foreach (int ints in integerListForeachCopy.ToList())
{
    if (ints % 2 == 0)
    {
        integerListForeachCopy.Remove(ints);
        Console.WriteLine(ints + "copy of the list ");
    }
}

Reverse foreach loop

List<int> integerListReverseForeach = new List<int>();
for (int i = 0; i < 10; i++)
{
    integerListReverseForeach.Add(i);
}
foreach (int ints in integerListReverseForeach.Reverse<int>())
{
    if (ints % 2 == 0)
    {
        integerListReverseForeach.Remove(ints);
        Console.WriteLine(ints + "reverse foreach");
    }
}

Just a few things that were confusing me and would like cleared up.

Thank you in advance.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Too many questions for one question -> too broad. "Best way" -> subjective – Tim Schmelter Sep 15 '16 at 12:01
  • 1
    You use reverse for-loops if you want to remove items, if you would remove them in a forward loop, the indexes would be wrong since the collection is getting smaller. – Tim Schmelter Sep 15 '16 at 12:03
  • Besides, modifying the list inside a loop results in a lot of pain, ie removing the *wrong* items. If you remove item 5 then index 6 ends up referring to a different item than before – Panagiotis Kanavos Sep 15 '16 at 12:03
  • I don't understand the 'reverse' bit. By the way to remove elements from a list (called ORIGINAL) you first have to select the items to remove and save them in a list (call this list TEMP), then you have to iterate on TEMP and remove items on ORIGINAL. – Mauro Sampietro Sep 15 '16 at 12:04
  • 1
    Yep - you can do things differently in C#... some are more productive than others, some are better at resource management or memory usage or (whatever), but "Best Way" depends on an unknowable number of variables. Maybe there's no difference, maybe there is but the difference doesn't matter to your application environment. It's all opinion unless you can specifiy a particular circumstance. – Shannon Holsinger Sep 15 '16 at 12:04
  • @sam modifying from the start results in index changes, which is why the only safe way to remove using indexes is from the end. – Panagiotis Kanavos Sep 15 '16 at 12:05
  • A better option may be to *not* modify the original list, simply select the items that should be kept and return *them* in a list. Results in safer code that is also thread-friendly – Panagiotis Kanavos Sep 15 '16 at 12:07
  • @PanagiotisKanavos why would you work with indexes at all? – Mauro Sampietro Sep 15 '16 at 12:17
  • @TimSchmelter apologies, I was just curious if there were certain circumstances where one might be used over the other, sort of if there was a 'rule of thumb' for each one. Thank you for answering one of the questions though. – Anonymous5642 Sep 15 '16 at 12:22

3 Answers3

2

Removing the items one by one seems like the least efficient way ( closer to quadratic O(n²) complexity ), but making a new list is closer to linear O(n) complexity:

var L = Enumerable.Range(0, 10).ToList();

L = L.Where(i => (i & 1) > 0).ToList();
//L = Enumerable.Range(0, L.Count / 2).Select(i => L[(i << 1) + 1]).ToList(); 
//L = Enumerable.Range(0, L.Count).Where(i => (i & 1) > 0).Select(i => L[i]).ToList();
//L.RemoveAll(i => (i & 1) == 0); // { 1, 3, 5, 7, 9 } // O(n)

Removing all items at once with .RemoveAll and .RemoveRange is O(n)

The answer here seems like the most efficient as it just moves the items without removing them, and then removes the extra items at the end: Removing alternate elements in a List<T>

Community
  • 1
  • 1
Slai
  • 22,144
  • 5
  • 45
  • 53
  • 2
    Removing M items from a list of size N is O(M * N) if you're removing them using `Remove`, and O(N) if removing them using `RemoveAll`. – Servy Sep 15 '16 at 13:42
1

The best way for removing items from a List<T> based on condition is using the RemoveAll method which is internally optimized for such operation:

var list = new List<int>();
for(int i = 0; i <10; i ++)
    list.Add(i);

list.RemoveAll(value => (value % 2) == 0);
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
0

Do it with LINQ, which will just go once through the list being very efficient.

var result = list.Where(x => (x % 2) != 0);

if you need to operate further on the given list, do (even tho it creates a new List with references):

list = list.Where(x => (x % 2) != 0).ToList();

Greetings

Konstantin

Slai
  • 22,144
  • 5
  • 45
  • 53
KoPoCabana
  • 80
  • 5