Find()とWhere()。FirstOrDefault()の比較


161

Where.FirstOrDefault()は、検索を実行して最初の要素を取得するために使用している人をよく見ます。なぜ使用しないのFind()ですか?他に利点はありますか?違いがわからなかった。

namespace LinqFindVsWhere
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> list = new List<string>();
            list.AddRange(new string[]
            {
                "item1",
                "item2",
                "item3",
                "item4"
            });

            string item2 = list.Find(x => x == "item2");
            Console.WriteLine(item2 == null ? "not found" : "found");
            string item3 = list.Where(x => x == "item3").FirstOrDefault();
            Console.WriteLine(item3 == null ? "not found" : "found");
            Console.ReadKey();
        }
    }
}

45
FWIWは、およびのlist.FirstOrDefault(x => x == "item3");両方.Whereを使用するよりも簡潔です.FirstOrDefault
カークウォル

@カーク、次の質問は、なぜ検索結果を追加したのかと思います。それは良いヒントです。私が考えられる唯一のことは、FirstOrDefaultがnull以外の異なるデフォルト値を返す可能性があるということです。そうでなければ、それは無意味な追加のように思えます。
KingOfHypocrites

8
FindLINQよりも古い。(それは.NET 2.0で利用可能で、ラムダを使用できませんでした。通常のメソッドまたは匿名メソッドを使用することを強制されました)
Kirk Woll

回答:


204

FindメソッドはどこにありIEnumerable<T>ますか?(修辞的な質問。)

WhereそしてFirstOrDefault方法は、以下を含む、配列の複数の種類に対して適用可能でありList<T>T[]Collection<T>器具は、その任意の配列などIEnumerable<T>、これらの方法を使用することができます。Findでのみ使用できますList<T>。一般的に適用性が高く、再利用性が高く、影響が大きい方法。

私の次の質問は、なぜ彼らがその検索結果を追加したのかと思います。それは良いヒントです。私が考えられる唯一のことは、FirstOrDefaultがnull以外の異なるデフォルト値を返す可能性があるということです。そうでなければ、それは無意味な追加のようです

Findon List<T>は他のメソッドよりも古いものです。List<T>.NET 2.0のジェネリックで追加されFind、そのクラスのAPIの一部でした。Whereそして、後の.NETバージョンであるLinqのFirstOrDefault拡張メソッドとして追加されましたIEnumerable<T>。Linqが2.0リリースに存在し、Find追加されなかったとは断言できませんが、それはおそらく、以前の.NETバージョンに含まれていた他の多くの機能で、後のバージョンで廃止または冗長化されたためです。


85
補足するだけです。WhereとFirstまたはFirstOrDefaultを呼び出す必要はありません。FirstまたはFirstOrDefaultのどちらかを使用すると、検索述語を指定できるため、Where呼び出しが不要になります
Robson Rocha

4
ただし、Where(condition).FirstOrDefault()最適化は少なくともFirstOrDefault(condition)単独で最適化する場合もあれば、最適化する場合もあります。Where()可能な場合は常に改善されたパフォーマンスを得るために使用します。
Suncat2000

7
@ Suncat2000で例を提供してください
コンスタンチン

2
@ Suncat2000その表現力のせいでLinqを使用していて、宣言型コードを書きたいと思っています。将来の実装で変更される可能性のある、このようなマイクロの改善について心配する必要はありません。また、早すぎる最適化は行わないでください
Piotr Falkowski

50

私は本日、80Kのオブジェクトのリストに対していくつかのテストを行っているFind()ことを知り、Wherewith を使用するよりも最大1000%高速であることがわかりましたFirstOrDefault()。それぞれの前後でタイマーをテストするまで、私はそれを知りませんでした。時々それは同じ時間でした、さもなければそれはより高速でした。


6
Where AND FirstOrDefaultで試しましたか?FirstOrDefaultだけで試してみて、Find()の方が優れているかどうかを確認してください。
MVCKarl

5
.ToList()またはで結果を具体化しなかったようですが.ToArray()、実際にクエリを実行しました。
Andrew Morton

4
これはFind、主キー(したがってインデックス)を使用するのに対しWhere、プレーンSQLクエリであるからです
percebus

4
EF6以降、FindとFirstOrDefaultはどちらもまったく同じSQLステートメントを生成します。context.Database.Log = Console.Write;を実行すると、コンソールアプリでSQLを確認できます。sitedの例は、主キーを持つDBに対してではなく、文字列のリストに対してメモリ内の「検索」を使用しています。おそらく、Find句のステートメント変換-ラムダ式の解析を行う必要がないため、この場合のパフォーマンスが向上します。データベースに対して、RLの状況の違いに気付くことはないと思います...また、2番目ではなく1番目に検索を使用してテストされたかどうかも
わかりませ

2
まあ、このパフォーマンスの改善は、find()がDBにアクセスする前にオブジェクトのキャッシュをチェックするのに対し、where()は常にDBに移動してオブジェクトを取得するためです
Gaurav

35

データのソースがEntity Frameworkである場合、非常に重要な違い があります。Find「永続化されていない」「追加された」状態のエンティティを検出しますが、そうしませWhereん。これは仕様によるものです。



1

Anthonyの回答に加えて Where()、すべてのレコードを訪問して結果を返しFind()ますが、述語が指定の述語と一致する場合は、すべてのレコードを走査する必要はありません。

たとえばid、とnameプロパティを持つテストクラスのリストがあるとします。

 List<Test> tests = new List<Test>();
 tests.Add(new Test() { Id = 1, Name = "name1" });
 tests.Add(new Test() { Id = 2, Name = "name2" });
 tests.Add(new Test() { Id = 3, Name = "name3" });
 tests.Add(new Test() { Id = 4, Name = "name2" }); 
 var r = tests.Find(p => p.Name == "name2");
 Console.WriteLine(r.Id);

の出力を提供し2、Findは2回のWhere().FirstOrDefault()アクセスでFindに結果を提供する必要がありますが、使用すると、すべてのレコードにアクセスし、結果を取得します。

したがって、コレクション内のレコードの最初の結果のみが必要であることがわかっている場合Find()は、より適切になります。Where().FirtorDefault();


4
ただし、Where()。FirstOrDefault()を使用すると、すべてのレコードにアクセスし、結果を取得します。いいえ。FirstOrDefaultチェーンを「バブルアップ」し、すべての列挙を停止します。より良い表現がないために「バブルアップ」という用語を使用します。これは、実際にはすべてのセレクター/述語が次のパスに渡されるため、チェーンの最後のメソッドが実際に最初に動作するためです。
Silvermind

1

うわー、今日YouTubeでMicrosofToolboxのEFチュートリアルを見るだけです。彼はクエリでFind()とFirstOrDefault(condition)を使用することについて述べ、Find()はそのオブジェクトに対して何かを実行したデータを検索します(追加または編集または削除-まだデータベースに保存されていません)一方、FirstOrDefaultはすでに保存されているものを探します


-1

Find()IEnumerableのと同等ですFirstOrDefault()。は.Where()を両方でチェーンしないでください。.FirstOrDefault()これは、.Where()が配列全体を調べ、そのリストを反復処理して最初の項目を見つけるためです。FirstOrDefault()メソッドに検索述語を入れることで、信じられないほどの時間を節約できます。

また、このスレッドへのリンクされた質問を読んで、.Find()特定のシナリオでのより良いパフォーマンスについて詳しく知ることをお勧めします。Find()とFirstOrDefault()のパフォーマンス


これはあなたの上の答えの複製です。また、その回答に関するSilvermindのコメントも参照してください。
carlin.scott
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.