Anel LINQ: Qualquer () vs Contém () para coleções enormes

103

Dada uma enorme coleção de objetos, há uma diferença de desempenho entre os itens a seguir?

Coleção.Contém :

myCollection.Contains(myElement)

Enumerable.Qualquer :

myCollection.Any(currentElement => currentElement == myElement)
SDReyes
fonte
7
Uma coleção de 10.000.000 de int's. o vencedor é o contém para 300%. mas vale a pena considerar as variações mencionadas abaixo.
SDReyes
1
Isso parece mostrar um forte contraste entre os dois: thedailywtf.com/Articles/State-of-the-UNION.aspx
David Peterson

Respostas:

143

Contains()é um método de instância e seu desempenho depende muito da própria coleção. Por exemplo, Contains()em a Listé O (n), enquanto Contains()em a HashSeté O (1).

Any()é um método de extensão e simplesmente percorrerá a coleção, aplicando o delegado em cada objeto. Portanto, tem uma complexidade de O (n).

Any()é mais flexível, pois você pode passar um delegado. Contains()só pode aceitar um objeto.

Etienne de Martel
fonte
27
Containstambém é um método de extensão contra IEnumerable<T>(embora algumas coleções também tenham seu próprio Containsmétodo de instância). Como você disse, Anyé mais flexível do que Containsporque você pode passar um predicado personalizado, mas Contains pode ser um pouco mais rápido porque não precisa executar uma invocação de delegado para cada elemento.
LukeH
1
Será Any () executar a operação em todos os objetos na coleção ou ele termina com o primeiro jogo?
Quarkly
1
Pelo menos de acordo com a fonte , ele para na primeira partida. All()opera de forma semelhante.
Etienne de Martel
13

Depende da coleção. Se você tem uma coleção ordenada, então Containspode fazer uma pesquisa inteligente (binária, hash, árvore b, etc.), enquanto com `Any () você basicamente fica preso na enumeração até encontrá-la (assumindo LINQ-to-Objects) .

Observe também que em seu exemplo, Any()está usando o ==operador que verificará a igualdade referencial, enquanto Containsusará IEquatable<T>ou o Equals()método, que pode ser substituído.

tster
fonte
4
Com .Any você pode comparar propriedades facilmente. Com .Contains, você pode apenas comparar objetos e precisa de um IEqualityComparer extra para comparar propriedades.
msfanboy
1
@msfanboy: É verdade, mas a pergunta era especificamente sobre o desempenho e mostrava a comparação de todo o objeto. Portanto, não acho que seja relevante aqui.
tster
4

Suponho que isso dependeria do tipo de myCollectioné que dita como Contains()é implementado. Se uma árvore binária classificada, por exemplo, ela poderia pesquisar de forma mais inteligente. Também pode levar em consideração o hash do elemento. Any()por outro lado, irá enumerar através da coleção até que o primeiro elemento que satisfaça a condição seja encontrado. Não há otimizações para se o objeto tivesse um método de pesquisa mais inteligente.

Jeff Mercado
fonte
0

Contains () também é um método de extensão que pode funcionar rapidamente se você usá-lo da maneira correta. Por ex:

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

Isso dará a consulta

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

enquanto Any (), por outro lado, sempre itera através do O (n).

Espero que isso funcione ....

Uwais
fonte