57

I know it probably doesnt matter/affect performance for the most part but I hate the idea of getting an IEnumerable and doing .Count(). Is there a IsEmpty or NotEmpty or some function? (similar to stl empty())

jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • 1
    Count can be very inefficient when checking for emptiness when the underlying collection is not an ICollection as it will count all elements before returning when all you want to know is there at least 1 element. – Bear Monkey Sep 23 '10 at 15:39
  • 1
    possible duplicate of [C#: Recommended way to check if a sequence is empty](http://stackoverflow.com/questions/2094729/c-recommended-way-to-check-if-a-sequence-is-empty) – nawfal Feb 18 '13 at 20:55

8 Answers8

86

You want IEnumerable.Any() extension method (.Net Framework 3.5 and above). It avoids counting over the elements.

John Cummings
  • 1,949
  • 3
  • 22
  • 38
cristobalito
  • 4,192
  • 1
  • 29
  • 41
  • 8
    To elaborate it counts at most 1 element and is very efficient. – Bear Monkey Sep 23 '10 at 15:30
  • 3
    "...and is very efficient" - it's efficiency depends on the implementation. If it's a lazy-evaluated enumeration (e.g. a method that uses yield), then even starting the enumeration can be costly. – Joe Sep 23 '10 at 15:36
  • 10
    Costly doesnt mean its not efficient. – Bear Monkey Sep 23 '10 at 15:44
  • 1
    If it's a lazy-evaluated enumerable, then counting it will be even more costly. In all cases, Any() will produce the answer more quickly than Count() because it succeeds (and stops processing) on the first successful result. – KeithS Sep 23 '10 at 15:49
  • @KeithS. I completely agree. But the point is that the cost of even starting the enumeration may be significant, and may even be much larger than the cost of actually doing the iteration. Any is better than Count, but you may need to consider whether instantiating a collection is more appropriate - see my answer. – Joe Sep 23 '10 at 15:54
  • @cristobalito: Will an extension method on an interface always be used, even if the class implementing the interface offers a method of the same name, or is there some way for a class that implements iEnumerable(of T) indicate that the class has its own definition for "Any"? – supercat Sep 23 '10 at 17:12
  • @supercat: not sure about that. No doubt the standard defines the precedence in such cases. Quickest way it find out would be to knock up a small sample app. – cristobalito Sep 23 '10 at 23:04
  • 7
    maybe I'm missing something, but the accepted response works if we have a IEnumerable not IEnumerable since Any requires a constraint. – Marcote Dec 01 '11 at 13:27
  • @Markust in order to resolve IsEmpty with IEnumerable use this: `enumerable.Cast().Any()` – shirbr510 Dec 18 '16 at 12:15
22

if it is not generic than something like this

enumeration.Cast<object>().Any();

if it's generic, use extension of Enumerable as was said already

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Artiom
  • 7,694
  • 3
  • 38
  • 45
12

Without any need of LINQ, you can do following:

bool IsEmpty(IEnumerable en)
{
    foreach(var c in en) { return false; }
    return true;
}
nothrow
  • 15,882
  • 9
  • 57
  • 104
  • 2
    Even faster would be return en.GetEnumerator().MoveNext(), which is basically what Any()'s implementation does. You're pretty much doing the same with the foreach, but you're incurring additional costs of assigning the first value to a local var, which you will never use. – KeithS Sep 23 '10 at 15:54
  • @KeithS: that's not very safe: an IEnumerable can be IDisposable as well (for several enumerables this is very relevant, for instance when you have a try-finally around your yield statements). foreach takes care you dispose properly. BTW, the method above is pretty much what `Any()` does. – Ruben Sep 23 '10 at 16:59
  • ok then, using(iter = en.GetIterator()) return iter.MoveNext(); You're still not assigning the current value like you would with a foreach. – KeithS Sep 23 '10 at 17:28
  • 3
    +2 Thanks for answering the question for non-generic IEnumerables! Resharper recommends: !items.Cast().Any(); – sky-dev Mar 10 '15 at 17:48
  • To clarify @Ruben's comment: its an *iterator* (IEnumerator) that gets created and disposed by `foreach`; you certainly don't want to dispose the *IEnumerable* itself - your caller probably still wants that. :) – ToolmakerSteve Nov 26 '18 at 16:50
4

You can use extension methods such as Any() or Count(). Count() is more costly than Any(), since it must execute the whole enumeration, as others have pointed out.

But in the case of lazy evaluation (e.g. a method that uses yield), either can be costly. For example, with the following IEnumerable implementation, each call to Any or Count will incur the cost of a new roundtrip to the database:

IEnumerable<MyObject> GetMyObjects(...)
{
    using(IDbConnection connection = ...)
    {
         using(IDataReader reader = ...)
         {
             while(reader.Read())
             {
                 yield return GetMyObjectFromReader(reader);
             }
         }
    }
}

I think the moral is:

  • If you only have an IEnumerable<T>, and you want to do more than just enumerate it (e.g. use Count or Any), then consider first converting it to a List (extension method ToList). In this way you guarantee to only enumerate once.

  • If you are designing an API that returns a collection, consider returning ICollection<T> (or even IList<T>) rather than IEnumerable<T> as many people seem to recommend. By doing so you are strengthening your contract to guarantee no lazy evaluation (and therefore no multiple evaluation).

Please note I am saying you should consider returning a collection, not always return a collection. As always there are trade-offs, as can be seen from the comments below.

  • @KeithS thinks you should never yield on a DataReader, and while I never say never, I'd say it's generally sound advice that a Data Access Layer should return an ICollection<T> rather than a lazy-evaluated IEnumerable<T>, for the reasons KeithS gives in his comment.

  • @Bear Monkey notes that instantiating a List could be expensive in the above example if the database returns a large number of records. That's true too, and in some (probably rare) cases it may be appropriate to ignore @KeithS's advice and return a lazy-evaluated enumeration, provided the consumer is doing something that is not too time-consuming (e.g. generating some aggregate values).

Joe
  • 122,218
  • 32
  • 205
  • 338
  • 3
    This is a bad example. You should NEVER yield on a DataReader, for reasons other than performance (it keeps locks in place longer, turns a "firehose" data stream into a trickle, etc). However, slurping all the data into a List, then yielding through it, would perform similarly and still illustrate the point. – KeithS Sep 23 '10 at 16:06
  • 1
    ToListing before returning could be even more costly than repeated instantiation costs if, for instance, the database return millions of records. Id rather return IEnumerable and let the consumer decide if they want to cache the results with ToList. Also what Keith said. – Bear Monkey Sep 23 '10 at 16:16
  • @KeithS I agree with your sentiment, and would not expose such a method in a public API for the reasons you mention and others. But the point here is simply to provide an artificial example of an extreme case where starting the enumeration may take much longer than actually enumerating. – Joe Sep 23 '10 at 16:20
  • @Bear Monkey. "ToListing ... could be ... more costly ... if... the database return millions of records". I absolutely agree. Which is why I said you should "consider" using ToList rather than "always" use ToList. – Joe Sep 23 '10 at 16:23
2

Keep in mind that IEnumerable is just an interface. The implementation behind it can be very different from class to class (consider Joe's example). The extension method IEnumerable.Any() has to be a generic approach and may not be what you want (performance wise). Yossarian suggests a means that should work for many classes, but if the underlying implementation does not use 'yield' you could still pay a price.

Generally, if you stick to collections or arrays wrapped in an IEnumerable interface, then Cristobalito and Yossarian probably have the best answers. My guess is the built-in .Any() ext method does what Yossarian recommends.

Les
  • 10,335
  • 4
  • 40
  • 60
1

On IEnumerable or IEnumerable<T>, no.

But it really doesn't make much sense. If a collection is empty and you try to iterate over it using IEnumerable, the call to IEnumerator.MoveNext() will simply return false at no performance cost.

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • "... at no performance cost" - if it's not a collection, but instead a lazy-evaluated enumeration, there may be a significant cost. – Joe Sep 23 '10 at 15:36
  • 1
    @Joe - But you're going to incur the same cost calling IEnumerable.Any() or IEnumerable.Count() as well. – Justin Niessner Sep 23 '10 at 15:50
  • I agree. Hence in some cases it's worth considering instantiating a list so that this cost is only incurred once. See my answer. – Joe Sep 23 '10 at 15:57
0

You can also write your own Count extension method overloads like so:

    /// <summary>
    /// Count is at least the minimum specified.
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="min"></param>
    /// <returns></returns>
    public static bool Count<TSource>(this IEnumerable<TSource> source, int min)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        return source.Count(min, int.MaxValue);
    }

    /// <summary>
    /// Count is between the given min and max values
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <param name="source"></param>
    /// <param name="min"></param>
    /// <param name="max"></param>
    /// <returns></returns>
    public static bool Count<TSource>(this IEnumerable<TSource> source, int min, int max)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        if (min <= 0)
        {
            throw new ArgumentOutOfRangeException("min", "min must be a non-zero positive number");
        }
        if (max <= 0)
        {
            throw new ArgumentOutOfRangeException("max", "max must be a non-zero positive number");
        }
        if (min >= max)
            throw new ArgumentOutOfRangeException("min and max", "min must be lest than max");

        var isCollection = source as ICollection<TSource>;

        if (isCollection != null)
            return isCollection.Count >= min && isCollection.Count <= max;

        var count = 0;
        using (var enumerator = source.GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                count++;
                if (count >= min && count <= max)
                    return true;
            }
        }
        return false;
    }
Jonathan Parker
  • 6,705
  • 3
  • 43
  • 54
-1

Use Enumerable.Empty() which rather than IEnumerable.Any() will prevent ending up having null list.

ali
  • 350
  • 2
  • 15
  • I think User wants easy way to check whether a IEnumerable is empty or not. Enumerable.Empty() returns an IEnumerable. But IEnumerable.Any() returns boolean value. Therefor I thinks relevant to this question IEnumerable.Any() is better. https://msdn.microsoft.com/en-us/library/bb341042(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/bb337697(v=vs.110).aspx – Menuka Ishan Apr 19 '17 at 08:00