关于c#:如何有效地确定IEnumerable是否包含多个元素?

How can I efficiently determine if an IEnumerable has more than one element?

给定一个初始化的IEnumerable

1
IEnumerable<T> enumerable;

我想确定它是否有多个元素。我认为最明显的方法是:

1
enumerable.Count() > 1

但是,我相信Count()列举了整个集合,这对于这个用例来说是不必要的。例如,如果集合包含大量元素或从外部源提供其数据,那么在性能方面这可能是非常浪费的。

如何在不枚举任何超过2个元素的情况下完成此操作?


通过结合System.Linq中的扩展方法,可以用多种方法测试这个问题。下面是两个简单的例子:

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

我更喜欢第一个,因为有一个常见的方法来检查Count() >= 1是否与Any()在一起,因此我发现它更可读。


为了好玩,调用next()两次,然后再获得一个IEnumerable。

或者,为这个特定的目标编写一个小包装类:EnumerablePrefetcher : IEnumerable以尝试在初始化时获取指定数量的项。

它的IEnumerable GetItems()方法应该以这种方式使用收益率。

1
2
3
4
5
6
7
8
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;
}


@Cameron-s的解决方案更简单,但下面的方案更有效。我根据Enumerable.Count()方法提出了这个问题。Skip()总是迭代而不是短路,以获得ICollectionICollection类型的source计数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/// <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;
                }
            }
        }
    }
    return false; // < count
}