26

I'd like to write:

IEnumerable<Car> cars;
cars.Find(car => car.Color == "Blue")

Can I accomplish this with extension methods? The following fails because it recursively calls itself rather than calling IList.Find().

public static T Find<T>(this IEnumerable<T> list, Predicate<PermitSummary> match)
{
    return list.ToList().Find(match);
}

Thanks!

Brian Low
  • 11,605
  • 4
  • 58
  • 63

3 Answers3

63

This method already exists. It's called FirstOrDefault

cars.FirstOrDefault(car => car.Color == "Blue");

If you were to implement it yourself it would look a bit like this

public static T Find<T>(this IEnumerable<T> enumerable, Func<T,bool> predicate) {
  foreach ( var current in enumerable ) {
    if ( predicate(current) ) {
      return current;
    }
  }
  return default(T);
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
10

Jared is correct if you are looking for a single blue car, any blue car will suffice. Is that what you're looking for, or are you looking for a list of blue cars?

First blue car:

Car oneCar = cars.FirstOrDefault(c => c.Color.Equals("Blue"));

List of blue cars:

IEnumerable<Car> manyCars = cars.FindAll(car => car.Color.Equals("Blue"));
bluish
  • 26,356
  • 27
  • 122
  • 180
StyxRiver
  • 2,225
  • 1
  • 16
  • 20
  • Thanks, and if you are looking for exactly one blue car: cars.Single(car => car.Color.Equals("Blue") – Brian Low Jun 03 '10 at 21:08
  • Single is okay if you are guaranteed to have ONLY ONE car in the entire list. If you have more than one car, or no cars at all, you're going to throw an InvalidOperationException. FirstOrDefault will return your blue car, or the default type (often null). First will throw an exception if there is nothing that matches the predicate. – StyxRiver Jun 03 '10 at 22:03
4

You know that Find(...) can be replaced by Where / First

IEnumerable<Car> cars;
var result = cars.Where(c => c.Color == "Blue").FirstOrDefault();

This'll return null in the event that the predicate doesn't match.

Aren
  • 54,668
  • 9
  • 68
  • 101