LINQ and counting

When we work with collections we often have to count the elements in some way. Sometimes we need to know how many elements there are or how many elements that  complies with some  condition.

So let’s assume that I have a collection ‘myCollection’ containing a number of elements. If we want to know how many elements is in the collection we will naturally write this:

var numberOfElements = myCollection.Count();

Counting

It is important to know that the only way the Count() method can know how many elements there are in the collection, is to enumerate through the collection. (unless the collection is an ICollection<T>). Count() is implemented like this (almost – I have removed some null checks):

public static int Count(this IEnumerable source) {
 //If the collection is of a type that implements the Count
 //property, then use that as there is a good chance that the Count property is
 //more efficient.
 ICollection collectionoft = source as ICollection;
 if (collectionoft != null) return collectionoft.Count;
 ICollection collection = source as ICollection;
 if (collection != null) return collection.Count;
 //Otherwise iterate through the collection until we reach the end
 int count = 0;
 using (IEnumerator e = source.GetEnumerator()) {
   checked {
     while (e.MoveNext()) count++;
    }
 }
 return count;
} 

The important part to note here, is that we should call Count() more times than strictly necessary, as we might need to iterate through the complete collection every time.

At least one – Any

I often se code like this:

if(myCollection.Count() >= 1)
  //… do stuff…

So we iterate through the complete collection just found out if there is at least one item in the collection. That seems like a waste, especially when there might be thousands or millions of items in the collection. Luckily there is an optimized method for that.

if(myCollection.Any())
  // … do stufff…

Which will produce the exact same result, but notice that Any() is implemented like this:

public static bool Any(this IEnumerable source) {
  using (IEnumerator e = source.GetEnumerator()) {
    if (e.MoveNext()) return true;
  }
  return false;
} 

So this will only iterate one item and so much more efficient.

None

Sometimes we want to know if there are no items that satisfies a certain condition. We can do this in a number of ways:

if(myCollection.Where(x => x > 5).Count() == 0)
  // … do stuff …

This is still inefficient for the same reasons as above.

if(myCollection.Where(x => x > 5).Any() ==false)
  // … do stufff …

This is more efficient, but a little hard to read –  instead I have implemented my own extension, called None(). So we can write

if(myCollection.Where(x => x > 5).None())
  // … do stuff …

It is implemented like this:

public static bool None(this IEnumerable source)
{
  return !source.Any();
}

I also implement an overload to match the version of Any() that takes a predicate.

public static bool None(this IEnumerable source,  Func<tsource, bool=""> predicate)
{
  return !source.Any(predicate);
}

This overload makes it possible to write either

if(myCollection.Where(x => x > 5).None())
  // … do stuff …

or

if(myCollection.None(x => x > 5))
  // … do stuff …

Exactly n or more than n

Sometimes we want to know if the collection has exactly 10 elements or more than 10 elements – and again it is a waste to use Count(), when only need to iterate over 10 elements to answer the question.

For this purpose I have these two methods, each in two versions:

public static bool ContainsExactly(this IEnumerable source,  int count)
{
  if (count < 0)
    throw new ArgumentOutOfRangeException("count");
  if (source == null)
    throw new ArgumentNullException("source");
  using (var e = source.GetEnumerator())
  {
    for (int i = 0; i < count; i++)
    {
      if (!e.MoveNext())
        return false;
    }
    return !e.MoveNext();
  }
}
public static bool ContainsExactly(this IEnumerable source,
                                            int count, Func<t, bool=""> predicate)
{
  return source.Where(predicate).ContainsExactly(count);
}
public static bool ContainsMoreThan(this IEnumerable source,
                                             int count)
{
  if (count < 0)
    throw new ArgumentOutOfRangeException("elementCount");
  if (source == null)
    throw new ArgumentNullException("source");
  return seq.Skip(count).Any();
}
public static bool ContainsMoreThan(this IEnumerable source,
                                             int count, Func<t, bool=""> predicate)
{
  return source.Where(predicate).ContainsMoreThan(count);
}
Advertisements

About Lund

Owner of iCodeIT, a software consulting company. I am primarily working the .NET development and architecture.
This entry was posted in C#, Linq and tagged , , , , , . Bookmark the permalink.

2 Responses to LINQ and counting

  1. Pingback: Best Practices for Linq Enumerables and Queryables « Zeros, Ones and a Few Twos

  2. Pingback: LINQ and iterating over null collections. | iCodeIT

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s