5

I remove item from ArrayList in foreach loop and get follwing exception.

Collection was modified; enumeration operation may not execute.

How can I remove items in foreach,

EDIT: There might be one item to remove or two or all.

Following is my code:

/*
 * Need to remove all items from 'attachementsFielPath' which does not exist in names array.
 */

try
{
    string attachmentFileNames = txtAttachment.Text.Trim(); // Textbox having file names.
    string[] names = attachmentFileNames.Split(new char[] { ';' });

    int index = 0;

    // attachmentsFilePath is ArrayList holding full path of fiels user selected at any time.
    foreach (var fullFilePath in attachmentsFilePath)
    {
        bool isNeedToRemove = true;

        // Extract filename from full path.
        string fileName = fullFilePath.ToString().Substring(fullFilePath.ToString().LastIndexOf('\\') + 1);

        for (int i = 0; i < names.Length; i++)
        {
        // If filename found in array then no need to check remaining items.
        if (fileName.Equals(names[i].Trim()))
        {
            isNeedToRemove = false;
            break;
        }
        }

        // If file not found in names array, remove it.
        if (isNeedToRemove)
        {
        attachmentsFilePath.RemoveAt(index);
        isNeedToRemove = true;
        }

        index++;
    }
}
catch (Exception ex)
{
    throw ex;
}

EDIT: Can you also advice on code. Do I need to break it into small methods and exception handling etc.

Invalid argument exception On creating generic list from ArrayList

foreach (var fullFilePath in new List<string>(attachmentsFilePath))

{

alt text

When I use List<ArrayList> the exception is Argument '1': cannot convert from 'System.Collections.ArrayList' to 'int'

attachmentsFilePath is declared like this

ArrayList attachmentsFilePath = new ArrayList();

But when I declared it like this, problem solved

List<ArrayList> attachmentsFilePath = new List<ArrayList>();
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Kashif
  • 14,071
  • 18
  • 66
  • 98

7 Answers7

6

Another way of doing it, start from the end and delete the ones you want:

List<int> numbers = new int[] { 1, 2, 3, 4, 5, 6 }.ToList();
for (int i = numbers.Count - 1; i >= 0; i--)
{
    numbers.RemoveAt(i);
}
Mikael
  • 602
  • 3
  • 9
5

You can't remove an item from a collection while iterating over it.

You can find the index of the item that needs to be removed and remove it after iteration has finished.

int indexToRemove = 0;

// Iteration start

if (fileName.Equals(names[i].Trim()))
{
    indexToRemove = i;
    break;
}

// End of iteration

attachmentsFilePath.RemoveAt(indexToRemove);

If, however, you need to remove more than one item, iterate over a copy of the list:

foreach(string fullFilePath in new List<string>(attachmentsFilePath))
{
    // check and remove from _original_ list
}
DavidRR
  • 18,291
  • 25
  • 109
  • 191
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 2
    Why not create a list of indexes to remove? – Michael Arnell Mar 30 '10 at 12:37
  • 2
    Storing a list of indexes is risky. You'll either have to iterate over the list of indexes in reverse or maintain an offset every time you remove an element. – Adam Robinson Mar 30 '10 at 12:41
  • 1
    Is creating a copy of collection to iterate is good approach? – Kashif Mar 30 '10 at 12:42
  • @Muhammad: That is the technique that I usually employ, though I'd also recommend moving to `List` rather than using `ArrayList`. – Adam Robinson Mar 30 '10 at 12:44
  • I have created new List(attachementsFilePath) and it give me invalid arguemnt exception. I have attached iamge in question area. – Kashif Mar 30 '10 at 13:25
  • What is the type of `attachementsFilePath`? The list should be of the same type. – Oded Mar 30 '10 at 13:41
  • It is ArrayList and I used but it gives exception in that case too, I have also used but same exception. – Kashif Mar 30 '10 at 14:01
  • When I use List the exception is Argument '1': cannot convert from 'System.Collections.ArrayList' to 'int' – Kashif Mar 30 '10 at 14:05
  • attachmentsFilePath is declared like this ArrayList attachmentsFilePath = new ArrayList(); But when I declared it like this, problem solved List attachmentsFilePath = new List(); – Kashif Mar 30 '10 at 14:15
2

You can iterate over a copy of the collection:

foreach(var fullFilePath in new ArrayList(attachmentsFilePath))
{
    // do stuff
}
jonnystoten
  • 7,055
  • 2
  • 28
  • 36
2
    List<string> names = new List<string>() { "Jon", "Eric", "Me", "AnotherOne" };
    List<string> list = new List<string>() { "Person1", "Paerson2","Eric"};

    list.RemoveAll(x => !names.Any(y => y == x));
    list.ForEach(Console.WriteLine);
Islam Yahiatene
  • 1,441
  • 14
  • 27
  • **Description:** This example uses a [LINQ](http://stackoverflow.com/tags/linq/info) approach to remove from `list` any item in `list` that does *not* exist in `names` ([see demo](http://ideone.com/QMkkpr)). Or in other words, this example outputs the *intersection* of `list` and `names` (which is just `Eric`). MSDN documentation for [List.RemoveAll](https://msdn.microsoft.com/en-us/library/wdka673a%28v=vs.110%29.aspx). – DavidRR Aug 07 '15 at 20:44
0

while enumerating (or using foreach) you cannot modify that collection. If you really want to remove items, then you can mark them and later remove them from list using its Remove method

ata
  • 8,853
  • 8
  • 42
  • 68
0

do the following:

foreach (var fullFilePath in new List(attachmentsFilePath))
{

this way you create a copy of the original list to iterate through

mfeingold
  • 7,094
  • 4
  • 37
  • 43
  • I have created new List(attachementsFilePath) and it give me invalid arguemnt exception. I have attached iamge in question area. – Kashif Mar 30 '10 at 13:29
0

You could loop over the collection to see which items need to be delete and store those indexes in a separate collection. Finally you would need to loop over the indexes to be deleted in reverse order and remove each from the original collection.

list<int> itemsToDelete

for(int i = 0; i < items.Count; i++)
{
    if(shouldBeDeleted(items[i]))
    {
        itemsToDelete.Add(i);
    }
}

foreach(int index in itemsToDelete.Reverse())
{
    items.RemoveAt(i);
}
Michael Arnell
  • 1,008
  • 1
  • 9
  • 16