У чому полягає користь .Any () у списку C # <>?


40

Я обговорював це з колегами, і ми не змогли зрозуміти, яка користь .Anyдля тих чи інших даних List<>у C #.

Ви можете перевірити дійсність елемента в масиві, як наступне твердження:

if (MyList.Any()){ ...}  //Returns true or false

Що точно таке саме

if (MyList.Count() != 0) { ... }

і є набагато більш поширеним, читабельним та зрозумілим щодо наміру ifзаяви.

Зрештою, ми застрягли в цій думці:

.Any() може бути використаний, буде працювати так само добре, але менш зрозуміло про наміри програміста, і в такому випадку його використовувати не слід.

Але ми вважаємо, що це не може бути правильним; ми повинні щось бракувати.

Чи ми?


40
Яким чином є менш зрозумілим у намірі?
jk.

35
Я заперечую вашу заяву, яка Any()є менш зрозумілою: Any()мені здається більш зрозумілою, особливо з умовою лямбда. Переклад коду англійською мовою в моїй голові if(MyList.Count(o => o > 10) > 0)стає "Чи кількість предметів на 10 перевищує 0?" тоді як if(MyList.Any(o => o > 10))стає "Чи є предмети більше 10?"
BlueRaja - Danny Pflughoeft

3
@SargeBorsch - лише якщо ви віддаєте перевагу Гескель / функціональне іменування, чого більшість людей не робить.
Давор Ждрало

4
@ BlueRaja-DannyPflughoeft я згоден. Я думаю, що будь-яке є більш зрозумілим, оскільки воно виключає те, що можна вважати магічним числом.
Енді

2
@SargeBorsch: SQL - паралельно AnyIS Exists. Ім'я Linq, ймовірно, більше натхнене Haskell та Python, які також мають будь-які / всі функції.
ЖакB

Відповіді:


95

Майте на увазі, що Anyне працює на a List; він працює на IEnumerable, який представляє конкретний тип, який може мати або не мати Countвластивість. Це правда, що це не обов'язково найкраще використовувати для List, але це, безумовно, стане в нагоді в кінці запиту LINQ. І навіть кориснішою, ніж окрема версія, є переоцінка, яка приймає присудок так само, як Where. Нічого, що вбудовано List, не існує так близько, як зручно чи виразно, як Anyметод розширення предикатів .

Крім того, якщо ви використовуєте Count()(метод розширення LINQ для IEnumerable), а не Count(властивість увімкнено List), він може перерахувати всю послідовність, якщо він не може оптимізувати цю проблему, виявивши, що ваш базовий тип даних має Countвластивість . Якщо у вас є довга послідовність, це може бути помітно падіння продуктивності , коли ви на самому ділі не піклуватися про те , що відлік, і просто хочу знати , якщо є якісь - або елементи в колекції.


19
Це. Продуктивність убік, Any()з присудком є більш виразним, ніж порівняння перебору, Enumerable.Count()що приймає присудок з 0. :)
Dan J,

1
Я думаю, що це пояснює основи так чітко, що пояснює відповідь у кращому випадку.
Тарік

2
ІМХО, Existsтакий же зручний і виразний, як Anyі присудок. Використання Count != 0властивості на a List- це нормальніше, ніж використання Any(). Це лише особисті переваги. Я також пройшов через зусилля зміни _list_.Count()в _list_.Countв коді моєї групи. Це зробило для мене помітну різницю.
Suncat2000

55

Різниця в часі виконання Count()може бути O (n), де Any()O (1).


15
Count()також не зупинятиметься на нескінченних ітераторах, поки Any()буде, оскільки його потрібно зателефонувати лише MoveNext()один раз.
Джон Перді

3
Короткий і точний, але це читається швидше як коментар, ніж відповідь. Програмісти віддають перевагу відповідям, які заглиблюються в причини і надають міру пояснення. Подумайте про редагування своєї відповіді та розширення питання, чому O (1) може бути (є) важливим.

дуже хороша відповідь щойно дізнався, я повинен використовувати будь-який замість count == 0: d
MonsterMMORPG

4
Any(Func<T>)is O (n)
BlueRaja - Danny Pflughoeft

1
У конкретному випадку Listефективність однакова, оскільки розширення використовує властивість. Вірно для всіх колекцій, що реалізують ICollectionінтерфейс.
Торкіл Холм-Якобсен

9

Власне, майте на увазі, що існує властивість List.Count , а потім є метод Enumerable.Count .

У вашому прикладі ви використовуєте Enumerable.Count()метод, який повинен повторити кожен елемент перерахунку, щоб повернути результат. Це явно повільніше, ніж дзвінок, Any()який потрібно лише повторити над першим елементом, якщо він існує.

Редагувати:

У коментарях було зазначено, що правильно, цей Enumerable.Count()метод розширення не потребує повторення через усі пункти, якщо він виявить, що перелічувальне число також буває an ICollection<T>. Так, у випадку з List<T>, використання Countвластивості чи методу насправді не має значення.

Джерело IEnumerable.Count :

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}

Досить справедливо. А як щодо використання властивості .Count тоді? Чи не зробить це читання значно швидшим, можливо, таким же швидким або навіть швидшим, ніж дзвінок .Any ()?
Gil Sand

4
За List<T>результатами різниця в продуктивності буде незначною. Тому просто використовуйте те, що вам більше подобається. Але для інших типів IEnumerables ви можете вибрати лише Count()(метод), і Any(), у цьому випадку, Any()завжди буде явним переможцем у вашому випадку використання, і йому слід віддати перевагу. Для чого це варто, я вважаю Any()цілком читабельним і зрозумілим.
sstan

@sstan так, якщо тільки якщо безлічі можна передати колекцію, то її можна оптимізувати, і це не має значення.
Есбен Сков Педерсен

2
Count()має таку ж складність, як і Countдля ICollections, оскільки метод розширення використовує властивість замість ітерації.
Торкіл Холм-Якобсен

Розширення Linq оптимізовані під відомі інтерфейси - IList, ICollection. Обговорення ефективності тут абсолютно
зайве

6

Дивовижне запитання - я вважаю, що намір list.Any()бути набагато чіткішим, ніж наміри list.Count()!=0.

Намір означає: Якщо ви читаєте код когось (а ви його самі не писали), чи цілком очевидно, чого хоче досягти програміст і чому це написано так, як це? Якщо загальна проблема вирішується непотрібно складним способом, ви одразу стаєте підозрілими і дивуєтесь, чому розробник не використовував простий спосіб. Ви переглядаєте код і намагаєтеся побачити, чи щось упустили. Ви боїтеся змінювати код, оскільки переживаєте, що у вас відсутній якийсь побічний ефект, і його зміна може спричинити несподівані проблеми.

Намір використання Any()методу цілком зрозумілий - ви хочете знати, чи є в списку елементи чи ні.

Намір виразу Count()!=0з іншого боку не є очевидним для читача. Звичайно, не важко помітити, що вираз підказує, чи список порожній чи ні. Питання виникають тому, що ви пишете це саме так, а не використовуєте стандартний метод. Чому ви використовуєте Count()явно? Якщо ви на самому справі просто потрібно знати , якщо є якісь - або переміщення об'єктів у списках, чому ви хочете , щоб порахувати весь список першим? Як тільки ви досягнете 1, у вас вже є відповідь. Якщо джерело був ітератором великої (можливо, нескінченної) колекції або переведений на sql, це може зробити велику різницю продуктивності. То, можливо, явне використання Count () полягає в тому, щоб змусити відкладений запит виконати або пройти ітератор?

Але джерелом насправді є List<T>де Count()O (1) і не має побічних ефектів. Але якщо код покладається на цю властивість List<T>, то чому б не використати властивість Count-property, яка більш чітко вказує на те, що ви очікуєте операції O (1) без побічних ефектів?

Як написано, list.Count()!=0робить саме те саме, що, list.Any()за винятком того, що це зайве складніше, а наміри незрозумілі.


Я читаю як: "Чи містить у собі список будь-яких предметів?" Count()має мається на увазі конверсію, яку я б не використовував, але це не ясно. Компілятор може оптимізувати його, що лише робить його недбалим кодуванням.
Suncat2000

2

Може, це просто слово? Anyє прикметником, насправді нічого не говорячи. Походить з Java, я б назвав його, isNonEmptyяке містить дієслово. Хлопець SQL може віддати перевагу EXISTS. Але, можливо, Anyнайкраще вписується в систему C #.

Яким би не був вибір слова, коли ти звикнеш до нього, воно повинно бути зрозумілішим. Ви б запитали "Чи залишилось more than zeroпивних пляшок". Чи очікуєте ви, що one or moreлюди почнуть їх рахувати, перш ніж вони відповідуть "Ні, немає any"?


1
Назва "будь-яка" має сенс, якщо ви думаєте про це з точки зору LINQ: Any()це дійсно ярлик дляAny(o => true)
BlueRaja - Danny Pflughoeft

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