C # Difference between First () and Find ()

So, I know that Find() is just a List<T> method, whereas First() is an extension for any IEnumerable<T> . I also know that First() will return the first element if the parameter is not passed, whereas Find() will throw an exception. Finally, I know that First() will throw an exception if the item is not found, whereas Find() will return the default value of the type.

I hope this confuses what I actually ask. This is a matter of computer science and applies to these methods at the computational level. I realized that IEnumerable<T> extensions do not always work as you would expect under the hood. So, here is Q, and I mean from the point "close to metal": what is the difference between Find() and First() ?

Here is some code to provide basic assumptions to work on this.

 var l = new List<int> { 1, 2, 3, 4, 5 }; var x = l.First(i => i == 3); var y = l.Find(i => i == 3); 

Is there any actual computational difference between the way First() and Find() find their values ​​in the above code?

Note. Let's now ignore things like AsParallel() and AsQueryable() .

+42
list c # linq
Dec 06 '10 at 17:12
source share
5 answers

Here is the code for List<T>.Find (from Reflector):

 public T Find(Predicate<T> match) { if (match == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); } for (int i = 0; i < this._size; i++) { if (match(this._items[i])) { return this._items[i]; } } return default(T); } 

And here is Enumerable.First :

 public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) { throw Error.ArgumentNull("source"); } if (predicate == null) { throw Error.ArgumentNull("predicate"); } foreach (TSource local in source) { if (predicate(local)) { return local; } } throw Error.NoMatch(); } 

Thus, both methods work approximately the same: they iterate over all the elements until they find one that matches the predicate. The only noticeable difference is that Find uses the for loop because it already knows the number of elements, and First uses the foreach loop because it doesn't know it.

+46
Dec 06 '10 at 17:17
source share

First will throw an exception when it does not find anything, FirstOrDefault , however, does the same as Find (except that it iterates through the elements).

+16
Dec 06 2018-10-06
source share

Since List<> not indexed in any way, it must go through all the values ​​to find a specific value. Therefore, this does not matter much in comparison with moving a list through an enumerated one (in addition to creating an instance of an enumerated auxiliary object).

However, keep in mind that the Find function was created earlier than the First extension method (Framework V2.0 vs. V3.5), and I doubt that they implemented Find if the List<> class was implemented simultaneously with the extension methods .

+1
Dec 6 '10 at 17:28
source share

Would it also be true that using β€œFind” in what is an enumerator rather than a list would have a potential execution cost, since the enumerator may not need to get the entire list to satisfy the predicate? Conversely, if you already have a list, then Find will be better.

0
Feb 01 '13 at 13:19
source share

BTW Find is rather equal to FirstOrDefault() than First() . Because if the predicate First() not satisfied with any list items, you will get an exception. Here, what dotpeek returns is another great replacement for the free reflector with some ReSharper features.

Here for the extension methods Enumerable.First(...) and Enumerable.FirstOrDefault(...) :

  public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (predicate(element)) return element; } return default(TSource); } public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw Error.ArgumentNull("source"); if (predicate == null) throw Error.ArgumentNull("predicate"); foreach (TSource element in source) { if (predicate(element)) return element; } throw Error.NoMatch(); } 

and here for List <>. Find:

 /// <summary> /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire <see cref="T:System.Collections.Generic.List`1"/>. /// </summary> /// /// <returns> /// The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type <paramref name="T"/>. /// </returns> /// <param name="match">The <see cref="T:System.Predicate`1"/> delegate that defines the conditions of the element to search for.</param><exception cref="T:System.ArgumentNullException"><paramref name="match"/> is null.</exception> [__DynamicallyInvokable] public T Find(Predicate<T> match) { if (match == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match); for (int index = 0; index < this._size; ++index) { if (match(this._items[index])) return this._items[index]; } return default (T); } 
0
Sep 02 '13 at 11:42 on
source share



All Articles