myermian
myermian

Reputation: 32505

Most efficient way to remove items from a list without running into a collection modified exception?

I have 2 lists:

ListA { 'A', 'B', 'C' } //ListA is DictA.Keys
ListB { 'B', 'X', 'Y' } //ListB is DictB.Keys

If I do ListA.Except(ListB) I get an ExceptIterator returned which will let me iterate over ListA for any item that isn't in ListB. The problem is that it's implementation is to simply use ListA as well (for some reason I thought it would create a new collection of items that are the difference). Well, low and behold I come to find out that it's still using ListA as the source, but simply using a special type of iterator. So, of course when I remove an item from ListA it complains that the collection has been modified.

I can think of a couple of ways to do what I want, first of which is to Copy ListA and do the Except on the copy. The second is to just do a while loop. I'm just wondering what the best solution to this problem is, and what follows standard guidelines.

If I'm going about this the wrong way, I'd love to know that. My key goal is to remove everything from a DictA that is not in DictB using the keys as comparisons.

Upvotes: 2

Views: 526

Answers (6)

GaryO
GaryO

Reputation: 1

If you are wanting the intersection of 2 dictionaries, then this is what you do:

IEnumerable<KeyValuePair<Char, String>> result = DictB.Intersect<KeyValuePair<Char, String>>(DictA);

This will return all items in DictA that match DictB. Also, for the example I assume the Keys were of type Char and the Values were of type String. If yours are different, just set the correct types for your solution. To see the actual result, you must either send result.GetEnumerator() or use it in a foreach statement.

Upvotes: 0

supercat
supercat

Reputation: 81123

If you can control the data structure in question, it may be useful to define a Purge method which accepts a predicate (a function which accepts the data type of the list and returns a Boolean) and removes all the items where the predicate returns true (I wish Microsoft had defined an IPurgeableCollection, since there would be no inherent difficulty implementing such a routine for many of the normal Microsoft collections). Note that in many cases, it would be much easier for a collection to implement a Purge method than to allow general modification during enumeration, and that in many cases such a method could not only avoid the need to create an extra copy of the data to be deleted, but it could also considerably reduce the amount of work required to perform the deletions (e.g. when purging a Dictionary, one wouldn't have to look up each key to be deleted, since one would have already found it during enumeration).

Upvotes: 0

Peter Ruderman
Peter Ruderman

Reputation: 12485

Maybe you're going about this backwards. Another way to say "remove everything from a DictA that is not in DictB" is to say "keep everything in DictA that is also in DictB". Instead of trying to remove things from ListA, just create a new list:

ListA.Join(ListB, ...);

Upvotes: 0

abatishchev
abatishchev

Reputation: 100248

For the same reason I use next:

ListA = ListA.Except(ListB).ToList();

Upvotes: 2

BrokenGlass
BrokenGlass

Reputation: 160852

Why not just use eager evaluation?

var myList = ListA.Except(ListB).ToList();

Upvotes: 2

Anthony Pegram
Anthony Pegram

Reputation: 126804

If you need the result to stick around and be independent of later changes, simply get a concrete result by invoking ToList() or ToArray() on the query.

var query = list1.Except(list2).ToList(); 

Changes to either source input will have no impact on your now fully-evaluated query.

Upvotes: 3

Related Questions