Anillo LINQ: Cualquiera () vs Contiene () para colecciones enormes

103

Dada una gran colección de objetos, ¿hay alguna diferencia de rendimiento entre los siguientes?

Colección Contiene :

myCollection.Contains(myElement)

Enumerable Cualquiera :

myCollection.Any(currentElement => currentElement == myElement)
SDReyes
fuente
7
Una colección de 10'000.000 de int's. el ganador es el contiene para el 300%. pero vale la pena considerar las variaciones que se mencionan a continuación.
SDReyes
1
Esto parece mostrar un marcado contraste entre los dos: thedailywtf.com/Articles/State-of-the-UNION.aspx
David Peterson

Respuestas:

143

Contains()es un método de instancia y su rendimiento depende en gran medida de la colección en sí. Por ejemplo, Contains()en a Listes O (n), mientras que Contains()en a HashSetes O (1).

Any()es un método de extensión, y simplemente recorrerá la colección, aplicando el delegado en cada objeto. Por tanto, tiene una complejidad de O (n).

Any()sin embargo, es más flexible ya que puede pasar un delegado. Contains()solo puede aceptar un objeto.

Etienne de Martel
fuente
27
Containstambién es un método de extensión contra IEnumerable<T>(aunque algunas colecciones también tienen su propio Containsmétodo de instancia). Como dice, Anyes más flexible que Containsporque puede pasarle un predicado personalizado, pero Contains podría ser un poco más rápido porque no necesita realizar una invocación delegada para cada elemento.
LukeH
1
¿ Any () realiza la operación en todos los objetos de la colección o termina con la primera coincidencia?
Quarkly
1
Al menos según la fuente , se detiene en el primer partido. All()opera de manera similar.
Etienne de Martel
13

Depende de la colección. Si tiene una colección ordenada, entonces Containspodría hacer una búsqueda inteligente (binaria, hash, árbol b, etc.), mientras que con `Any () básicamente está atascado con la enumeración hasta que la encuentre (asumiendo LINQ-to-Objects) .

También tenga en cuenta que en su ejemplo, Any()está usando el ==operador que verificará la igualdad de referencia, mientras Containsque usará IEquatable<T>o el Equals()método, que podría ser anulado.

tster
fuente
4
Con .Any puedes comparar propiedades fácilmente. Con .Contains puede comparar objetos y necesita un IEqualityComparer adicional para comparar propiedades.
msfanboy
1
@msfanboy: Eso es cierto, pero la pregunta era específicamente sobre el rendimiento y mostraba la comparación de todo el objeto. Entonces no creo que sea relevante aquí.
tster
4

Supongo que dependerá del tipo de myCollectiones el que dicta cómo Contains()se implementa. Si, por ejemplo, un árbol binario ordenado, podría buscar de forma más inteligente. También puede tener en cuenta el hash del elemento. Any()por otro lado se enumerará a través de la colección hasta que se encuentre el primer elemento que satisfaga la condición. No hay optimizaciones para si el objeto tenía un método de búsqueda más inteligente.

Jeff Mercado
fuente
0

Contains () también es un método de extensión que puede funcionar rápidamente si lo usa de la manera correcta. Por ejemplo:

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

Esto le dará a la consulta

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

mientras que Any () por otro lado siempre itera a través de O (n).

Espero que esto funcione ...

Uwais
fuente