Remove Values From Dictionary while Looping Through Values

  • Thread starter Thread starter O.B.
  • Start date Start date
O

O.B.

I need the ability to parse through the values of a Dictionary and
remove certain ones depending on their attribute values. In the example
below, an InvalidOperationException is thrown in the foreach statement
when the first item is removed from the Dictionary.

From looking at Dictionary's methods, I couldn't find anything to
create a copy of the Values before starting the foreach loop. Help?


static void someTest() {
Dictionary<String, Int32> storage = new Dictionary<string, Int32>();
for (int i = 0; i < 100; i++) {
String bar = "Test" + i;
Int32 foo = new Int32();
foo = i;
storage.Add(bar, foo);
}
foreach (Int32 tmp in storage.Values) {
if ((tmp % 5) == 0) {
String bar = "Test" + tmp;
storage.Remove(bar);
}
}
}
 
"O.B." <[email protected]> a écrit dans le message de (e-mail address removed)...

|I need the ability to parse through the values of a Dictionary and
| remove certain ones depending on their attribute values. In the example
| below, an InvalidOperationException is thrown in the foreach statement
| when the first item is removed from the Dictionary.

You cannot modify any list that is running an enumerator of iterator. You
need to use :

for (int i = list.count - 1; i >= 0; i--)
...

to ensure that items removed do not upset the iteration.

Joanna
 
O.B. said:
I need the ability to parse through the values of a Dictionary and remove
certain ones depending on their attribute values. In the example below, an
InvalidOperationException is thrown in the foreach statement when the first
item is removed from the Dictionary.

From looking at Dictionary's methods, I couldn't find anything to create a
copy of the Values before starting the foreach loop. Help?

You cannot modify a container without invalidating all active enumerators -
hence breaking your foreach statement. For a dictionary, what you need to
do is to build a list of keys to be deleted, then use a second loop through
that list to remove items from the dictionary.

static void someTest() {
Dictionary<String, Int32> storage = new Dictionary<string, Int32>();
for (int i = 0; i < 100; i++) {
String bar = "Test" + i;
Int32 foo = new Int32();
foo = i;
storage.Add(bar, foo);
}

List<string> keysToDelete = new List<string>();
foreach (Int32 tmp in storage.Values) {
if ((tmp % 5) == 0) {
String bar = "Test" + tmp;
keysToDelete.Add(bar);
}
}
foreach (string key in keysToDelete) {
storage.Remove(key);
}
}

-cd
 
Carl said:
You cannot modify a container without invalidating all active enumerators -
hence breaking your foreach statement. For a dictionary, what you need to
do is to build a list of keys to be deleted, then use a second loop through
that list to remove items from the dictionary.

static void someTest() {
Dictionary<String, Int32> storage = new Dictionary<string, Int32>();
for (int i = 0; i < 100; i++) {
String bar = "Test" + i;
Int32 foo = new Int32();
foo = i;
storage.Add(bar, foo);
}

List<string> keysToDelete = new List<string>();
foreach (Int32 tmp in storage.Values) {
if ((tmp % 5) == 0) {
String bar = "Test" + tmp;
keysToDelete.Add(bar);
}
}
foreach (string key in keysToDelete) {
storage.Remove(key);
}
}

This got me going in the right direction. The following is a little
more compact:

Given entityDatase as a Dictionary<long, MyClass>:

MyClass[] tempList = new MyClass[entityDatabase.Count];
entityDatabase.Values.CopyTo(tempList, 0);

foreach (MyClass tmp in tempList) {
if (tmp.invalid) {
entityDatabase.Remove(tmp);
}
}
 
O.B. said:
Carl said:
You cannot modify a container without invalidating all active enumerators -
hence breaking your foreach statement. For a dictionary, what you need to
do is to build a list of keys to be deleted, then use a second loop through
that list to remove items from the dictionary.

static void someTest() {
Dictionary<String, Int32> storage = new Dictionary<string, Int32>();
for (int i = 0; i < 100; i++) {
String bar = "Test" + i;
Int32 foo = new Int32();
foo = i;
storage.Add(bar, foo);
}

List<string> keysToDelete = new List<string>();
foreach (Int32 tmp in storage.Values) {
if ((tmp % 5) == 0) {
String bar = "Test" + tmp;
keysToDelete.Add(bar);
}
}
foreach (string key in keysToDelete) {
storage.Remove(key);
}
}

This got me going in the right direction. The following is a little
more compact:

Given entityDatase as a Dictionary<long, MyClass>:

MyClass[] tempList = new MyClass[entityDatabase.Count];
entityDatabase.Values.CopyTo(tempList, 0);

foreach (MyClass tmp in tempList) {
if (tmp.invalid) {
entityDatabase.Remove(tmp);
}
}

Well, yes, it's more compact, but it ends up copying a lot more
information than it has to. Carl's solution is one of the two
"standard" solutions to this problem, the other one given by Joanna is
iterating through a list in reverse. For the case of a Dictionary I
would choose Carl's method.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top