EnumerableExtensions.IsEmpty()

Sep 10, 2009 at 3:22 PM
Edited Sep 10, 2009 at 3:22 PM

There is already an extension in .NET that does this... it's not the .Count() as the comment in this function indicates:

// Don't use Enumerable.Count() because that will walk the entire sequence

unnecessarily.

It's the .Any() extension. It will test if the sequence is empty without enumerating the whole thing like .Count() might do.

http://msdn.microsoft.com/en-us/library/bb534972.aspx (notice "The enumeration of source is stopped as soon as the result can be determined." in the Remarks section)

Coordinator
Sep 10, 2009 at 10:52 PM

@alonzofox-

This is a good catch. We've gotten feedback that this and SelectWIthIndex (accidentally) duplicate behavior that is found in the BCL. It looks like we got a little carried away when creating extensions, and those two are my bad! We'll be deprecating them shortly, and eventually removing them in future versions.

Thanks for the feedback!

-Chris

Nov 11, 2009 at 10:18 AM

Internally, the .Any() does exactly what your IsEmpty method does.

Using how the IsEmpty method works gave me some inspiration of adding some more effecient methods for looking at counts, and as a result I have written a number Count comparison methods that make used of the GetEnumerator method to iterate over an IEnumerable, but can exit early rather than having to iterate over the whole list to do Count comparisons.  Examples are show below.

public static bool CountEqualTo<TSource>(this IEnumerable<TSource> source, int value) {
            
            ArgumentHelper.AssertNotNull(source, "source", "Source can not be null.");
            ArgumentHelper.AssertIntValue(0, () => value < 0, "value", "Value under test must be zero or greater.");
            
            var counter = 0;
            
            //Iterate over the items, counting as we go.  At each iteration we check the counter
            //value against out test value, and if it is greater, then count not equal, so retun false;
            using(var enumerator = source.GetEnumerator()) {

                while(enumerator.MoveNext()) {

                    counter++;

                    if(counter > value)
                        return false;
                }
                
                //if here it means that either we did not have an enumerator 
                //or counter vallue was not greater that out test value, so now simple compare results.
                return counter == value;
            }
        }

        /// <summary>
        /// A more efficient way of determine wether the item count of an IEnumerable{T} is less than a given value.
        /// </summary>
        /// <remarks>
        /// When you use Count() on an IEnumerable{T} the whole list needs to be iterated before count can be called.
        /// Using this method, iteration can stop as soon as the item count is greater than out test value
        /// so the whole list does not need to be iterated.
        /// </remarks>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static bool CountLessThan<TSource>(this IEnumerable<TSource> source, int value) {
            
            ArgumentHelper.AssertNotNull(source, "source", "Source can not be null.");
            ArgumentHelper.AssertIntValue(0, () => value < 0, "value", "Value under test must be zero or greater.");

            var counter = 0;

            //Iterate over the items, counting as we go.  Continue to count all the time we have an iterator
            //and out counter value is less than out test value.
            using(var enumerator = source.GetEnumerator()) {

                //only count while out counter is less that value under test
                while(enumerator.MoveNext() && counter <= value) {

                    counter++;
                }

                return counter < value;
            }
        }

        /// <summary>
        /// A more efficient way of determine wether the item count of an IEnumerable{T} is greater than a given value.
        /// </summary>
        /// <remarks>
        /// When you use Count() on an IEnumerable{T} the whole list needs to be iterated before count can be called.
        /// Using this method, iteration can stop as soon as the item count is greater than out test value
        /// so the whole list does not need to be iterated.
        /// </remarks>
        /// <typeparam name="TSource">The type of the source.</typeparam>
        /// <param name="source">The source.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static bool CountGreaterThan<TSource>(this IEnumerable<TSource> source, int value) {

            ArgumentHelper.AssertNotNull(source, "source", "Source can not be null.");
            ArgumentHelper.AssertIntValue(0, () => value < 0, "value", "Value under test must be zero or greater.");
            
            //if(value < 0)
            //    throw new ArgumentException("Value under test must be zero or greater.", "value");

            var counter = 0;

            //Iterate over the items, counting as we go.  Continue to count all the time we have an iterator
            using(var enumerator = source.GetEnumerator()) {

                while(enumerator.MoveNext()) {

                    counter++;
                    //as soon as our counter is greater than test value, we can return true;
                    if(counter > value)
                        return true;
                }

                //if here out counter can not be greater than our test value, therefore return false;
                return false;
            }
        }
Please feel free to use or suggest any improvements.
Nov 11, 2009 at 2:46 PM

Just seen that we can improve on these.  As Count() works in LINQ, we can test to see if our IEnumerable is an ICollection, and is so make use of the Count property.  As follows:

public static bool CountEqualTo<TSource>(this IEnumerable<TSource> source, int value) {
            
            ArgumentHelper.AssertNotNull(source, "source", "Source can not be null.");
            ArgumentHelper.AssertIntValue(0, () => value < 0, "value", "Value under test must be zero or greater.");

            //if our IEnumerable<TSource> can be cast to ICollection<TSource> we can make use
            //of the count property of collection as this is efficient.
            var collection = source as ICollection<TSource>;

            if(collection != null) {
                return collection.Count == value;
            }

            var counter = 0;
            
            //Iterate over the items, counting as we go.  At each iteration we check the counter
            //value against out test value, and if it is greater, then count not equal, so retun false;
            using(var enumerator = source.GetEnumerator()) {

                while(enumerator.MoveNext()) {

                    counter++;

                    if(counter > value)
                        return false;
                }
                
                //if here it means that either we did not have an enumerator 
                //or counter vallue was not greater that out test value, so now simple compare results.
                return counter == value;
            }
        }