Anello LINQ: Any () vs Contains () per enormi collezioni


103

Data una vasta collezione di oggetti, c'è una differenza di prestazioni tra i seguenti?

Collezione . Contiene :

myCollection.Contains(myElement)

Enumerable.Any :

myCollection.Any(currentElement => currentElement == myElement)

7
Una collezione di 10.000.000 di int. vincitore è il contiene per il 300%. ma vale la pena considerare le variazioni menzionate di seguito.
SDReyes

1
Questo sembra mostrare un netto contrasto tra i due: thedailywtf.com/Articles/State-of-the-UNION.aspx
David Peterson

Risposte:


143

Contains()è un metodo di istanza e le sue prestazioni dipendono in gran parte dalla raccolta stessa. Ad esempio, Contains()su a Listè O (n), mentre Contains()su a HashSetè O (1).

Any()è un metodo di estensione e passerà semplicemente attraverso la raccolta, applicando il delegato a ogni oggetto. Ha quindi una complessità di O (n).

Any()è tuttavia più flessibile poiché è possibile passare un delegato. Contains()può accettare solo un oggetto.


27
Containsè anche un metodo di estensione contro IEnumerable<T>(sebbene alcune raccolte abbiano anche il proprio Containsmetodo di istanza). Come dici tu, Anyè più flessibile rispetto al Containsfatto che puoi passargli un predicato personalizzato, ma Contains potrebbe essere leggermente più veloce perché non è necessario eseguire una chiamata di delegato per ogni elemento.
Luca H

1
Vuol Qualsiasi () eseguire l'operazione su tutti gli oggetti della collezione o lo fa terminare con la prima partita?
Quarkly

1
Almeno secondo la fonte , si ferma alla prima partita. All()funziona in modo simile.
Etienne de Martel

13

Dipende dalla collezione. Se hai una raccolta ordinata, Containspotresti fare una ricerca intelligente (binario, hash, b-tree, ecc.), Mentre con `Any () sei fondamentalmente bloccato con l'enumerazione finché non la trovi (assumendo LINQ-to-Objects) .

Nota anche che nel tuo esempio, Any()sta usando l' ==operatore che verificherà l'uguaglianza referenziale, mentre Containsuserà IEquatable<T>o il Equals()metodo, che potrebbe essere sovrascritto.


4
Con .Any puoi confrontare facilmente le proprietà. Con .Contains puoi semplicemente confrontare gli oggetti e hai bisogno di un IEqualityComparer extra per confrontare le proprietà.
msfanboy

1
@msfanboy: È vero, ma la domanda riguardava specificamente le prestazioni e mostrava il confronto dell'intero oggetto. Quindi non penso che sia rilevante qui.
tster

4

Suppongo che dipenda dal tipo di myCollectionè che determina come Contains()viene implementato. Se un albero binario ordinato, ad esempio, potrebbe cercare in modo più intelligente. Inoltre potrebbe prendere in considerazione l'hash dell'elemento. Any()d'altra parte enumererà attraverso la raccolta fino a trovare il primo elemento che soddisfa la condizione. Non ci sono ottimizzazioni per se l'oggetto avesse un metodo di ricerca più intelligente.


0

Contains () è anche un metodo di estensione che può funzionare velocemente se lo si utilizza nel modo corretto. Ad esempio:

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

Questo darà la query

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

mentre Any () d'altra parte itera sempre attraverso O (n).

Spero che funzioni ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.