Какой "лучший" (принимая во внимание скорость и удобочитаемость) способ определить, пуст ли список? Даже если список относится к типу IEnumerable<T>
и не имеет свойства Count.
Прямо сейчас я бросаюсь между этим:
if (myList.Count() == 0) { ... }
и это:
if (!myList.Any()) { ... }
Я предполагаю, что второй вариант быстрее, так как он вернется с результатом, как только увидит первый элемент, тогда как второй вариант (для IEnumerable) должен будет посетить каждый элемент, чтобы вернуть счет.
При этом второй вариант кажется вам читаемым? Что бы вы предпочли? Или вы можете придумать лучший способ проверить пустой список?
Ответ Edit @ lassevk кажется наиболее логичным, в сочетании с небольшой проверкой времени выполнения, чтобы использовать кешированный счетчик, если это возможно, например:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
is
иcast
но использованиеas
иnull
проверить:ICollection<T> collection = list as ICollection<T>; if (collection != null) return colllection.Count;
list.Any()
эквивалентноlist.IsEmpty
? Следует оптимизировать метод фреймворка - писать новый стоит только в том случае, если вы поняли, что это узкое место в производительности.IsEmpty
метод расширения. github.com/dotnet/corefx/issues/35054 Пожалуйста, проверьте и проголосуйте, если хотите и согласны.Ответы:
Вы могли сделать это:
Изменить : обратите внимание, что простое использование метода .Count будет быстрым, если у базового источника действительно есть свойство fast Count. Допустимая оптимизация, приведенная выше, будет заключаться в обнаружении нескольких базовых типов и простом использовании их свойства .Count вместо подхода .Any (), но затем откат к .Any (), если нет гарантии.
источник
IsNullOrEmpty()
.return !source?.Any() ?? true;
Я бы сделал одно небольшое дополнение к коду, на котором вы, кажется, остановились: проверьте также
ICollection
, поскольку это реализовано даже некоторыми не устаревшими универсальными классами (например,Queue<T>
иStack<T>
). Я бы также использовалas
вместо этого,is
поскольку это более идиоматично и, как было показано, быстрее .источник
NotSupportedException
илиNotImplementedException
. Я впервые использовал ваш пример кода, когда обнаружил, что коллекция, которую я использую, вызвала исключение для графа (кто знал ...).Вас это удивляет? Я предполагаю, что для
IList
реализацийCount
просто считывает количество элементов напрямую, при этомAny
он должен запроситьIEnumerable.GetEnumerator
метод, создать экземпляр и вызватьMoveNext
хотя бы один раз./ РЕДАКТИРОВАТЬ @Matt:
Да, конечно. Вот что я имел в виду. На самом деле он использует
ICollection
вместо,IList
но результат тот же.источник
Я только что написал небольшой тест, попробуйте следующее:
Второй почти в три раза медленнее :)
При повторной попытке теста секундомера со стеком или массивом или в других сценариях это действительно зависит от типа списка, который кажется, потому что они доказывают, что Count работает медленнее.
Думаю, это зависит от типа списка, который вы используете!
(Чтобы отметить, я поместил 2000+ объектов в список, и счет был еще быстрее, в отличие от других типов)
источник
Enumerable.Count<T>()
имеет специальную обработку дляICollection<T>
. Если вы попробуете это с чем-то другим, кроме базового списка, я ожидаю, что вы увидите значительно другие (более медленные) результаты.Any()
останется примерно таким же.Enumerable.Any<T>()
for нет специальной обработкиICollection<T>
? конечно, без параметровAny()
можно просто проверитьCount
свойствоICollection<T>
?List.Count
равно O (1) согласно документации Microsoft:http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
так что просто используйте
List.Count == 0
его намного быстрее, чем запросЭто связано с тем, что у него есть элемент данных с именем Count, который обновляется каждый раз, когда что-то добавляется или удаляется из списка, поэтому, когда вы вызываете
List.Count
его, не нужно перебирать каждый элемент для его получения, он просто возвращает элемент данных.источник
Второй вариант будет намного быстрее, если у вас несколько предметов.
Any()
возвращается, как только будет найден 1 предмет.Count()
должен продолжать просматривать весь список.Например, предположим, что в перечислении было 1000 элементов.
Any()
проверит первый, а затем вернет true.Count()
вернет 1000 после прохождения всего перечисления.Это потенциально хуже, если вы используете одно из переопределений предиката - Count () все равно должен проверять каждый элемент, даже если есть только одно совпадение.
Вы привыкаете использовать Any one - он имеет смысл и удобочитаем.
Одно предостережение - если у вас есть List, а не просто IEnumerable, используйте свойство Count этого списка.
источник
@Konrad меня удивляет то, что в своих тестах я передаю список в метод, который принимает
IEnumerable<T>
, поэтому среда выполнения не может оптимизировать его, вызывая метод расширения Count () дляIList<T>
.Я могу только предположить, что метод расширения Count () для IEnumerable делает что-то вроде этого:
... другими словами, небольшая оптимизация времени выполнения для особого случая
IList<T>
./ EDIT @Konrad +1 приятель - вы правы, скорее всего, он включен
ICollection<T>
.источник
Хорошо, а что насчет этого?
РЕДАКТИРОВАТЬ: Я только что понял, что кто-то уже набросал это решение. Было упомянуто, что это сделает метод Any (), но почему бы не сделать это самому? С уважением
источник
using
блок, поскольку в противном случае вы построилиIDisposable
объект, а затем отказались от него. Затем, конечно, он станет более лаконичным, если вы воспользуетесь уже существующим методом расширения и просто измените его наreturn !enumerable.Any()
(который делает именно это).Any()
именно это и выполняется, поэтому добавление точно такого же метода с другим именем просто сбивает с толку.Еще одна идея:
Однако мне больше нравится подход Any ().
источник
Это было критически важно, чтобы заставить это работать с Entity Framework:
источник
Если я проверяю с помощью Count (), Linq выполняет «SELECT COUNT (*) ..» в базе данных, но мне нужно проверить, содержат ли результаты данные, я решил ввести FirstOrDefault () вместо Count ();
Перед
После
источник
источник
Вот моя реализация ответа Дэна Тао с учетом предиката:
источник
источник
myList.ToList().Count == 0
, Вот и всеисточник
У меня работает этот метод расширения:
источник