LINQ Ring: Any () vs Contains () pour d'énormes collections

103

Étant donné une énorme collection d'objets, y a-t-il une différence de performances entre les éléments suivants?

Collection.Contient :

myCollection.Contains(myElement)

Énumérables .

myCollection.Any(currentElement => currentElement == myElement)
SDReyes
la source
7
Une collection de 10'000.000 d'int. le gagnant est le contient pour 300%. mais il vaut la peine de considérer les écarts mentionnés ci-dessous.
SDReyes
1
Cela semble montrer un contraste frappant entre les deux: thedailywtf.com/Articles/State-of-the-UNION.aspx
David Peterson

Réponses:

143

Contains()est une méthode d'instance et ses performances dépendent en grande partie de la collection elle-même. Par exemple, Contains()sur a Listest O (n), tandis que Contains()sur a HashSetest O (1).

Any()est une méthode d'extension, et passera simplement par la collection, en appliquant le délégué sur chaque objet. Il a donc une complexité de O (n).

Any()est cependant plus flexible puisque vous pouvez passer un délégué. Contains()ne peut accepter qu'un objet.

Etienne de Martel
la source
27
Containsest également une méthode d'extension contre IEnumerable<T>(bien que certaines collections aient également leur propre Containsméthode d'instance). Comme vous le dites, Anyest plus flexible que Containsparce que vous pouvez lui transmettre un prédicat personnalisé, mais Contains peut être légèrement plus rapide car il n'a pas besoin d'effectuer un appel de délégué pour chaque élément.
LukeH
1
Est -ce que Tout () effectuer l'opération sur tous les objets de la collection ou ne terminé avec le premier match?
Quarkly le
1
Au moins selon la source , il s'arrête sur le premier match. All()fonctionne de manière similaire.
Etienne de Martel le
13

Cela dépend de la collection. Si vous avez une collection ordonnée, vous Containspouvez faire une recherche intelligente (binaire, hachage, b-tree, etc.), tandis qu'avec `Any () vous êtes fondamentalement coincé avec l'énumération jusqu'à ce que vous la trouviez (en supposant LINQ-to-Objects) .

Notez également que dans votre exemple, Any()utilise l' ==opérateur qui vérifiera l'égalité référentielle, tandis que Containsutilisera IEquatable<T>ou la Equals()méthode, qui pourrait être remplacée.

tster
la source
4
Avec .Any, vous pouvez facilement comparer les propriétés. Avec .Contains, vous pouvez simplement comparer des objets et vous avez besoin d'un IEqualityComparer supplémentaire pour comparer les propriétés.
msfanboy
1
@msfanboy: C'est vrai, mais la question portait spécifiquement sur les performances et montrait la comparaison de l'objet entier. Je ne pense donc pas que ce soit pertinent ici.
tster le
4

Je suppose que cela dépendrait du type de système myCollectionqui dicte la manière dont il Contains()est mis en œuvre. Si un arbre binaire trié par exemple, il pourrait rechercher plus intelligemment. Il peut également prendre en compte le hachage de l'élément. Any()d'autre part, l'énumérera à travers la collection jusqu'à ce que le premier élément qui satisfait la condition soit trouvé. Il n'y a pas d'optimisation pour savoir si l'objet avait une méthode de recherche plus intelligente.

Jeff Mercado
la source
0

Contains () est également une méthode d'extension qui peut fonctionner rapidement si vous l'utilisez correctement. Par exemple:

var result = context.Projects.Where(x => lstBizIds.Contains(x.businessId)).Select(x => x.projectId).ToList();

Cela donnera la requête

SELECT Id FROM Projects INNER JOIN (VALUES (1), (2), (3), (4), (5)) AS Data(Item) ON Projects.UserId = Data.Item

tandis que Any () d'un autre côté itère toujours à travers le O (n).

J'espère que cela fonctionnera ....

Uwais
la source