开发者

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.


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.


Why not just use eager evaluation?

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


For the same reason I use next:

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


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, ...);


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).


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜