web-dev-qa-db-ja.com

First()とFind()のC#の違い

したがって、Find()は_List<T>_メソッドのみであるのに対して、First()は_IEnumerable<T>_の拡張機能であることがわかります。パラメータが渡されない場合、First()は最初の要素を返し、Find()は例外をスローすることもわかっています。最後に、要素が見つからない場合はFirst()が例外をスローし、Find()は型のデフォルト値を返すことを知っています。

これで、私が実際に求めていることについての混乱が解消されることを願っています。これはコンピューターサイエンスの質問であり、これらの方法を計算レベルで扱います。 _IEnumerable<T>_拡張機能は、内部で期待されるように常に動作するとは限らないことを理解しました。 Qがあります。「金属に近い」という観点から言うと、Find()First()の違いは何ですか?

この質問に対応するための基本的な前提を提供するコードを次に示します。

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

First()Find()が上記のコードで値を検出する方法に実際の計算上の違いはありますか?

注:現時点では、AsParallel()AsQueryable()などを無視しましょう。

52
Squirrelsama

List<T>.Findのコードは次のとおりです(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);
}

そして、ここに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();
}

したがって、どちらの方法もほぼ同じように機能します。つまり、述語に一致するものが見つかるまですべての項目を繰り返します。唯一の顕著な違いは、Findは要素数を既に知っているためforループを使用し、Firstはそれを知らないためforeachループを使用することです。

55
Thomas Levesque

Firstは何も見つからなかった場合に例外をスローしますが、FirstOrDefaultFindとまったく同じように動作します(要素を反復処理する方法は別として)。

19
Doggett

BTW FindはFirstOrDefault()ではなくFirst()と同等です。 First()の述語がリスト要素に満足していない場合、例外が発生するためです。ここでは dotpeek を返します。これは、ReSharperの機能のいくつかを備えた別の優れた無料のリフレクターの代替品です

Enumerable.First(...)および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();
    }

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);
}
5
python_kaa

List<>はどのような方法でも索引付けされていません。特定の値を見つけるには、すべての値を調べる必要があります。したがって、列挙可能なヘルパーオブジェクトインスタンスの作成を除き、列挙可能なリストを介してリストを走査する場合と比べて、大きな違いはありません。

とはいえ、Find関数はFirst拡張メソッド(Framework V2.0 vs. V3.5)よりもずっと前に作成されたものであり、Find if List<>クラスは、拡張メソッドと同時に実装されていました。

2
Lucero

1- Find()は、エンティティがコンテキストにない場合にNullを返しますが、First()は例外をスローします
2- Find()は、コンテキストに追加されたが、まだデータベースに保存されていないエンティティを返します

2
Omid