geek yapping

Twitter












Remove<T>(this IList<T> source, Func<T,bool> selector) why not?

Maybe I am just crazy, but it seems like removing or deleting items from a collection is always an after thought.  Take IList for example, a list of items, with the ability to add and remove from it.  We have a flurry of extension methods that are inherited from IEnumerable to add items but it seems like no one thought maybe it would be nice to beef up the remove method with some extension methods.  Maybe I missed an extension namespace, maybe I am just crazy.  How many times do we have to write the following bloated code just to remove something from a collection?

 

var ingredient = Ingredients.FirstOrDefault(i => i.FeedId == feed.Id);
Ingredients.Remove(ingredient);

Even worse, is when we want to remove multiple items from a list based on some criteria. I have to add a foreach loop of some sort to remove each item one at a time. Oh and, deal with the always wonderful: (System.InvalidOperationException: Collection was modified; enumeration operation may not execute). So, I have to remember to create a new list to avoid this dreadful mistake:

var ingredients = Ingredients.Where(i => i.FeedId == feed.Id).ToList();
foreach (var ingredient in Ingredients)
{
	Ingredients.Remove(ingredient);
}

Of course, now that I have created a new list, ToList(), I can simplify this to:

var ingredients = Ingredients.Where(i => i.FeedId == feed.Id).ToList();
ingredients.ForEach(i=> Ingredients.Remove(i));

But that is still icky, all that code just to remove an item or a set of items? So enough complaining on my part, it's time to put up or shut up. This is what I want to do in code:

Ingredients.Remove(i => i.FeedId == feed.Id);

Simple, right? And to do this here is the simple extension method:

public static void Remove<T>(this IList<T> source, Func<T, bool> selector)
{
	if (source == null || selector == null)
	{
		return;
	}

	var itemsToRemove = source.Where(selector).ToList();
	itemsToRemove.ForEach(i => source.Remove(i));
}

Now, I no longer have to worry about all these things when I want to remove items based on searching my list:

  • Doing a separate search for the items I want to remove
  • Creating a new list, avoiding the pitfall of enumerating when removing and getting "Collection was modified" exceptions.
  • Iterating over those items and calling remove on each

Some purists out there would be mad that I just quietly allow the source/selector to be null and not throw an exception. That's how I chose to implement this, if you want different behavior that's great. Just make sure you add this extension method to your arsenal! Maybe another RemoveSingle that throws an exception if it finds 0 or more than 1 item would be appropriate to add as well?

Happy coding!



Feedback

No comments posted yet.