Find () vs Where (). FirstOrDefault ()

161

Je vois souvent des gens utiliser Where.FirstOrDefault()pour faire une recherche et saisir le premier élément. Pourquoi ne pas simplement utiliser Find()? Y a-t-il un avantage à l'autre? Je ne pouvais pas faire de différence.

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();
        }
    }
}
KingOfHypocrites
la source
45
FWIW, list.FirstOrDefault(x => x == "item3");est plus concis que d'utiliser à la fois .Whereet .FirstOrDefault.
Kirk Woll
@Kirk, je suppose que ma prochaine question serait de savoir pourquoi ont-ils ajouté la trouvaille. C'est un bon conseil. La seule chose à laquelle je peux penser est que FirstOrDefault pourrait renvoyer une valeur par défaut différente autre que null. Sinon, cela semble être un ajout inutile.
KingOfHypocrites
8
Findest antérieur à LINQ. (il était disponible en .NET 2.0 et vous ne pouviez pas utiliser lambdas. Vous étiez obligé d'utiliser des méthodes normales ou anonymes)
Kirk Woll

Réponses:

205

Où est la Findméthode IEnumerable<T>? (Question rhétorique.)

Les Whereet FirstOrDefaultméthodes sont applicables contre plusieurs types de séquences, y compris List<T>, T[], Collection<T>, etc. Toute séquence qui met en œuvre IEnumerable<T>peuvent utiliser ces méthodes. Findest disponible uniquement pour le List<T>. Des méthodes généralement plus applicables, sont alors plus réutilisables et ont un impact plus important.

Je suppose que ma prochaine question serait de savoir pourquoi ont-ils ajouté la découverte. C'est un bon conseil. La seule chose à laquelle je peux penser est que FirstOrDefault pourrait renvoyer une valeur par défaut différente autre que null. Sinon, cela semble être un ajout inutile

Findsur List<T>est antérieur aux autres méthodes. List<T>a été ajouté avec des génériques dans .NET 2.0, et Findfaisait partie de l'API de cette classe. Whereet FirstOrDefaultont été ajoutés comme méthodes d'extension pour IEnumerable<T>avec Linq, qui est une version ultérieure de .NET. Je ne peux pas dire avec certitude que si Linq existait avec la version 2.0, cela Findn'aurait jamais été ajouté, mais c'est sans doute le cas pour de nombreuses autres fonctionnalités fournies dans les versions antérieures de .NET qui ont été rendues obsolètes ou redondantes par les versions ultérieures.

Anthony Pegram
la source
85
Juste pour compléter: il n'est pas nécessaire d'appeler Where and First ou FirstOrDefault: First ou FirstOrDefault vous permet de spécifier un prédicat de recherche, ce qui rend l'appel Where inutile
Robson Rocha
4
Mais Where(condition).FirstOrDefault()optimise au moins aussi bien et parfois mieux que FirstOrDefault(condition)seul. Nous utilisons toujours Where()pour obtenir des performances améliorées lorsqu'elles sont disponibles.
Suncat2000
7
@ Suncat2000 donne un exemple s'il vous plaît
Konstantin Salavatov
2
@ Suncat2000 Vous utilisez Linq en raison de sa puissance expressive et vous souhaitez écrire du code déclaratif. Vous ne devriez pas vous soucier de ces micro-améliorations, qui peuvent également changer dans les futures implémentations. Aussi, n'optimisez pas trop tôt
Piotr Falkowski
50

Je viens de le découvrir aujourd'hui, en faisant des tests sur une liste d'objets 80K et j'ai trouvé que cela Find()peut être jusqu'à 1000% plus rapide que d'utiliser un Whereavec FirstOrDefault(). Je ne savais pas cela avant de tester une minuterie avant et après tout. Parfois c'était le même moment, sinon c'était plus rapide.

digiben
la source
6
L'avez-vous essayé avec Where AND FirstOrDefault? Si vous l'avez peut-être essayé avec seulement FirstOrDefault et voyez si Find () est toujours meilleur.
MVCKarl
5
Il semble que vous n'ayez pas matérialisé le résultat avec un .ToList()ou .ToArray()pour exécuter réellement la requête.
Andrew Morton
4
C'est parce qu'il Findutilise les clés primaires (donc les index), alors que Wherec'est une simple requête SQL
percebus
4
À partir d'EF6, Find et FirstOrDefault génèrent tous deux exactement les mêmes instructions SQL. Vous pouvez voir le SQL dans une application console en faisant context.Database.Log = Console.Write; L'exemple localisé utilise en mémoire "Rechercher" par rapport à une liste de chaînes, sans aller à l'encontre d'une base de données avec des clés primaires. Peut-être que la traduction de l'instruction de la clause Find - qui omet la nécessité de faire une analyse d'expression lambda est la raison de l'amélioration des performances dans ce cas. Contre une base de données, je doute que vous remarquiez une différence dans les situations RL ... Je me demande aussi si elle a été testée en utilisant Find first au lieu de second ...
C.List
2
Eh bien, cette amélioration des performances est due au fait que find () vérifie dans le cache un objet avant de frapper DB alors que where () doit toujours aller DB pour obtenir un objet
Gaurav
35

Il y a une différence très importante si la source des données est Entity Framework: Findtrouvera les entités dans l'état «ajouté» qui ne sont pas encore persistantes, mais Wherene le seront pas. C'est par conception.

Crayeux
la source
1

en plus d'Anthony, répondez à la Where()visite de tous les enregistrements, puis retournez le (s) résultat (s) sans Find()avoir besoin de parcourir tous les enregistrements si le prédicat correspond au prédicat donné.

alors disons que vous avez List of Test class id et des namepropriétés.

 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);

Donnera la sortie de 2 , et seulement 2 visites Find nécessaire pour donner le résultat, mais si vous utilisez, Where().FirstOrDefault()nous visiterons tous les enregistrements et nous obtiendrons des résultats.

Ainsi, lorsque vous savez que vous ne voulez que le premier résultat des enregistrements de la collection, ce Find()sera plus approprié alorsWhere().FirtorDefault();

M Muneeb Ijaz
la source
4
mais si vous utilisez Where (). FirstOrDefault () nous visiterons tous les enregistrements et nous obtiendrons des résultats. Nan. FirstOrDefaultva «remonter» la chaîne et arrêter de tout énumérer. J'utilise le terme «bulle» par manque d'une meilleure expression, car en fait, chaque sélecteur / prédicat sera transmis au suivant, donc la dernière méthode de la chaîne fait en fait le travail en premier.
Silvermind
1

Wow, je viens de regarder le tutoriel EF de MicrosofToolbox aujourd'hui sur Youtube. Il a dit à propos de l'utilisation de Find () et FirstOrDefault (condition) dans la requête et Find () recherchera les données que vous avez effectuées sur cet objet (ajouter, modifier ou supprimer - mais pas encore enregistrées dans la base de données), tandis que FirstOrDefault ne le fera que cherchez ce qui a déjà été sauvegardé

Nguyen Khanh
la source
-1

Find()est l'équivalent IEnumerable de a FirstOrDefault(). Vous ne devez pas enchaîner les deux .Where () avec, .FirstOrDefault()car le .Where()parcourt tout le tableau puis parcourra cette liste pour trouver le premier élément. Vous gagnez un temps incroyable en mettant votre prédicat de recherche dans leFirstOrDefault() méthode.

De plus, je vous encourage à lire la question liée à ce fil pour en savoir plus sur les meilleures performances d'utilisation de .Find()dans des scénarios spécifiques Performance de Find () vs FirstOrDefault ()

Coup de fouet
la source
Ceci est un double de la réponse ci-dessus la vôtre. Voir également le commentaire de Silvermind sur cette réponse.
carlin.scott le