Кільце LINQ: Будь-яке () проти Містить () для величезних колекцій


103

Враховуючи величезну колекцію об'єктів, чи є різниця в продуктивності між наступними?

Колекція.Контейнери :

myCollection.Contains(myElement)

Численні .

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

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 може бути трохи швидшим, оскільки йому не потрібно виконувати виклик делегата для кожного елемента.
ЛукаХ

1
Чи будь-який () виконує операцію над усіма об'єктами колекції чи він закінчується першим збігом?
Quarkly

1
Принаймні за даними джерела , він зупиняється на першому поєдинку. All()діє аналогічно.
Етьєн де Мартель

13

Це залежить від колекції. Якщо у вас є впорядкована колекція, Containsви можете зробити інтелектуальний пошук (двійковий, хеш, b-дерево тощо), тоді як з пунктом `Any () ви в основному затримані до перерахування, поки не знайдете його (припускаючи LINQ-to-Objects) .

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


4
З. Кожен ви можете легко порівняти властивості. З .Contains ви можете просто порівнювати об'єкти, і вам потрібен додатковий IEqualityComparer для порівняння властивостей.
msfanboy

1
@msfanboy: Це правда, але питання стосувалося продуктивності та показало порівняння всього об'єкта. Тому я не думаю, що це актуально тут.
tster

4

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


0

Містить () - це також метод розширення, який може швидко працювати, якщо використовувати його правильно. Наприклад:

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).

Сподіваюся, це спрацює….

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.