Кольцо LINQ: Any () vs Contains () для огромных коллекций

104

Учитывая огромную коллекцию объектов, есть ли разница в производительности между следующими?

Коллекция. Содержит :

myCollection.Contains(myElement)

Enumerable.Any :

myCollection.Any(currentElement => currentElement == myElement)
SDReyes
источник
7
Коллекция из 10 000 000 инт. Победитель содержит 300%. но стоит рассмотреть упомянутые ниже различия.
SDReyes
1
Кажется, это демонстрирует разительный контраст между ними: thedailywtf.com/Articles/State-of-the-UNION.aspx
Дэвид Петерсон

Ответы:

143

Contains()- это метод экземпляра, и его производительность во многом зависит от самой коллекции. Например, Contains()на a List- O (n), а Contains()на a HashSet- O (1).

Any()является методом расширения и будет просто проходить через коллекцию, применяя делегат к каждому объекту. Следовательно, он имеет сложность O (n).

Any()однако более гибкий, поскольку вы можете передать делегата. Contains()может принимать только объект.

Этьен де Мартель
источник
27
Containsтакже является методом расширения против IEnumerable<T>(хотя в некоторых коллекциях тоже есть собственный Containsметод экземпляра). Как вы говорите, Anyэто более гибко, чем Containsпотому, что вы можете передать ему настраиваемый предикат, но Contains может быть немного быстрее, потому что не нужно выполнять вызов делегата для каждого элемента.
LukeH,
1
Выполняет ли Any () операцию со всеми объектами в коллекции или завершается с первым совпадением?
Quarkly
1
По крайней мере согласно источнику , он останавливается на первом совпадении. All()действует аналогично.
Этьен де Мартель
13

Это зависит от коллекции. Если у вас есть упорядоченная коллекция, вы Containsможете выполнить интеллектуальный поиск (двоичный, хэш, b-дерево и т. Д.), В то время как с `Any () вы в основном застряли в перечислении, пока не найдете его (при условии LINQ-to-Objects) .

Также обратите внимание, что в вашем примере Any()используется ==оператор, который будет проверять ссылочное равенство, в то время как Containsбудет использовать IEquatable<T>или Equals()метод, который может быть переопределен.

tster
источник
4
С .Any вы можете легко сравнивать свойства. С .Contains вы можете просто сравнивать объекты, и вам понадобится дополнительный IEqualityComparer для сравнения свойств.
msfanboy
1
@msfanboy: Это правда, но вопрос был конкретно о производительности и показал сравнение всего объекта. Поэтому я не думаю, что здесь это актуально.
tster 04
4

Я полагаю, это будет зависеть от типа того myCollection, как это Contains()будет реализовано. Например, в отсортированном двоичном дереве можно было бы искать более умный поиск. Также может учитываться хэш элемента. Any()с другой стороны, будет перечислять в коллекции, пока не будет найден первый элемент, удовлетворяющий условию. Нет никакой оптимизации, если бы у объекта был более умный метод поиска.

Джефф Меркадо
источник
0

Contains () также является методом расширения, который может работать быстро, если вы используете его правильно. Например:

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

Это даст запрос

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

в то время как Any (), с другой стороны, всегда выполняет итерацию через O (n).

Надеюсь, это сработает ....

Uwais
источник