Какая польза от .Any () в C # List <>?

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 - Дэнни Пфлугхофт
3
@SargeBorsch - только если вы предпочитаете Heskel / функциональное именование, что большинство людей не делают.
Давор Идрало
4
@ BlueRaja-DannyPflughoeft Я согласен. Я думаю, что любой более понятен, поскольку устраняет то, что можно считать магическим числом.
Энди
2
@SargeBorsch: SQL параллельный Anyесть Exists. Имя Linq, вероятно, больше вдохновлено Haskell и Python, которые также имеют любые / все функции.
JacquesB

Ответы:

95

Имейте в виду, что Anyне работает на List; он действует на объект IEnumerable, который представляет конкретный тип, который может иметь или не иметь Countсвойство. Это правда, что это не обязательно лучшая вещь для использования List, но она определенно пригодится в конце запроса LINQ. И даже более полезным, чем автономная версия, является переопределение, которое принимает предикат так же, как Where. Нет ничего Listболее удобного и выразительного, чем Anyметод расширения предикатов .

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

Мейсон Уилер
источник
19
Это. Помимо производительности, Any()с предикатом более выразительно, чем сравнение переопределения, Enumerable.Count()которое требует предикат с 0. :)
Дэн Дж.
1
Я думаю, что это объясняет основы настолько ясно, что в лучшем случае объясняет ответ.
Тарик
2
ИМХО, Existsтак же удобно и выразительно, как Anyи с предикатом. Использование Count != 0свойства для 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>)это O (n)
BlueRaja - Дэнни Пфлюгофт
1
В конкретном случае Listпроизводительность одинакова, поскольку расширение использует это свойство. Правда для всех коллекций, реализующих ICollectionинтерфейс.
Торкил Холм-Якобсен
9

На самом деле, имейте в виду, что есть свойство List.Count , а затем есть метод Enumerable.Count .

В вашем примере вы используете Enumerable.Count()метод, который должен перебирать каждый элемент перечисления, чтобы вернуть результат. Это явно медленнее, чем вызов, Any()который должен перебирать только первый элемент, если он существует.

РЕДАКТИРОВАТЬ:

В комментариях было правильно указано, что Enumerable.Count()методу расширения не нужно перебирать все элементы, если он обнаруживает, что перечислимое также оказывается 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;
}
sstan
источник
Справедливо. А как насчет использования свойства .Count тогда? разве это не сделает чтение значительно быстрее, может быть так же быстро или даже быстрее, чем вызов .Any ()?
Джил Сэнд
4
При List<T>этом разница в производительности будет незначительной. Так что просто используйте то, что вы предпочитаете. Но для других типов IEnumerables вы можете выбирать только Count()(метод), и Any(), и в этом случае, Any()всегда будете явным победителем в вашем случае использования, и его следует отдавать предпочтение. Для чего это стоит, я думаю Any(), вполне читабельно и понятно.
СЕНТ
@sstan да, если только перечисляемое не может быть приведено к сбору, его можно оптимизировать, и это не будет иметь значения.
Эсбен Сков Педерсен
2
Count()имеет ту же сложность, что и Countдля ICollections, так как метод расширения затем использует свойство вместо итерации.
Торкил Холм-Якобсен
Расширения Linq оптимизированы для известных интерфейсов - IList, ICollection. Обсуждение производительности здесь совершенно излишне, даже если это детали реализации
Gusdor
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()он, без необходимости, более сложен, а цель неясна.

JacquesB
источник
Я читаю оба как, "список содержит какие-либо элементы?" Count()имеет подразумеваемое преобразование, которое я бы избегал использовать, но это не ясно. Компилятор может оптимизировать его, что делает его неосторожным кодированием.
Suncat2000
2

Может это просто слово? Anyэто прилагательное, на самом деле ничего не говоря. Исходя из Java, я бы назвал это, isNonEmptyкоторый содержит глагол. Парень SQL может предпочесть EXISTS. Но, возможно, Anyлучше всего подходит в системе C #.

Каким бы ни было слово «выбор», как только вы к нему привыкнете, оно должно быть понятнее. Вы спросите: "Остались ли more than zeroпивные бутылки"? Вы ожидаете, что one or moreлюди начнут считать их прежде, чем они ответят "Нет, нет any"?

maaartinus
источник
1
Название «любой» имеет смысл, когда вы думаете об этом с точки зрения LINQ: Any()это действительно сокращение дляAny(o => true)
BlueRaja - Дэнни Пфлугхофт
Я обычно не использовал бы empty, чтобы описать, если перечислимому нужно что-либо перечислить. Но «есть ли что- то, что можно перечислить», мне кажется естественным, и Any работает против любого перечисления.
Энди