Подтвердить что ты не робот

Как я могу эффективно определить, имеет ли IEnumerable несколько элементов?

Учитывая инициализированный IEnumerable:

IEnumerable<T> enumerable;

Я хотел бы определить, имеет ли он несколько элементов. Я думаю, что самый очевидный способ сделать это:

enumerable.Count() > 1

Однако, я считаю, что Count() перечисляет всю коллекцию, которая не нужна для этого случая использования. Например, если коллекция содержит очень большое количество элементов или предоставила свои данные из внешнего источника, это может быть довольно расточительным с точки зрения производительности.

Как я могу сделать это без перечисления более чем двух элементов?

4b9b3361

Ответ 1

Вы можете проверить это разными способами, объединив методы расширения в System.Linq... Ниже приведены два простых примера:

bool twoOrMore = enumerable.Skip(1).Any();
bool twoOrMoreOther = enumerable.Take(2).Count() == 2;

Я предпочитаю первый, так как обычный способ проверить, есть ли Count() >= 1 с Any(), и поэтому я считаю его более читаемым.

Ответ 2

Для удовольствия, дважды нажмите Next(), затем получите еще один IEnumerable.

Или напишите небольшой класс-оболочку для этой конкретной цели: EnumerablePrefetcher : IEnumerable<T>, чтобы попытаться извлечь указанное количество элементов при инициализации.

Его метод IEnumerable<T> GetItems() должен использовать возврат возврата таким образом

foreach (T item in prefetchedItems) // array of T, prefetched and decided if IEnumerable has at least n elements
{
  yield return item;
}
foreach (T item in otherItems) // IEnumerable<T>
{
  yield return item;
}

Ответ 3

Решение @Cameron-S проще, но ниже более эффективно. Я придумал это на основе метода Enumerable.Count(). Skip() всегда будет повторяться, а не замыкаться, чтобы получить счет source для типа ICollection или ICollection<T>.

/// <summary>
/// Returns true if source has at least <paramref name="count"/> elements efficiently.
/// </summary>
/// <remarks>Based on int Enumerable.Count() method.</remarks>
public static bool HasCountOfAtLeast<TSource>(this IEnumerable<TSource> source, int count)
{
    source.ThrowIfArgumentNull("source");
    var collection = source as ICollection<TSource>;
    if (collection != null)
    {
        return collection.Count >= count;
    }
    var collection2 = source as ICollection;
    if (collection2 != null)
    {
        return collection2.Count >= count;
    }
    int num = 0;
    checked
    {
        using (var enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                num++;
                if (num >= count)
                {
                    return true;
                }
            }
        }
    }
    // returns true for source with 0 elements and count 0
    return num == count;
}