Any, Single, Multiple and Count

by Alex Siepman 26. May 2012 17:20

Problem

In a collection we can easily check if there is any (particular) item:

int[] numbers = { 5, 4, 1, 4, 9, 8, 6, 7, 2, 0 };
var anyNumbers = numbers.Any();
var anyNumber6 = numbers.Any(n => n == 6);

This is a very efficient way to check because it doesn't enumerate the whole collection. After enumerating the first element, the Any() method returns the result. This saves time if the collection is large or enumeration goes slow.

We still have to enumerate the whole collection if we need to know if a collection has one element, multiple elements or we need to compare the count. This is not efficient.

Solution

I created methods that counts the elements but not the whole collection. You can use it like this:

var numberIsSingle = numbers.IsSingle();
var numberIsMultiple = numbers.IsMultiple(n => n == 4);
var isExact = numbers.CountEquals(4);
var isMany = numbers.CountGreaterThan(4);
var isFew = numbers.CountGreaterThan(4, n => n <= 2);

This is the implementation of the methods

public static bool IsSingle<T>(this IEnumerable<T> source)
{
    return source.CountEquals(1); ;
}

public static bool IsMultiple<T>(this IEnumerable<T> source)
{
    return source.CountGreaterThan(1);
}

public static bool IsSingle<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.CountEquals(1, predicate);
}

public static bool IsMultiple<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    return source.CountGreaterThan(1, predicate);
}

public static bool CountGreaterThan<T>(this IEnumerable<T> source, int value)
{
    return source.CountCompareTo(value) > 0;
}

public static bool CountEquals<T>(this IEnumerable<T> source, int value)
{
    return source.CountCompareTo(value) == 0;
}

public static bool CountLowerThan<T>(this IEnumerable<T> source, int value)
{
    return source.CountCompareTo(value) < 0;
}

public static bool CountGreaterThan<T>(this IEnumerable<T> source, int value, Func<T, bool> predicate)
{
    return source.CountCompareTo(value, predicate) > 0;
}

public static bool CountEquals<T>(this IEnumerable<T> source, int value, Func<T, bool> predicate)
{
    return source.CountCompareTo(value, predicate) == 0;
}

public static bool CountLowerThan<T>(this IEnumerable<T> source, int value, Func<T, bool> predicate)
{
    return source.CountCompareTo(value, predicate) < 0;
}

private static int CountCompareTo<T>(this IEnumerable<T> source, int value, Func<T, bool> predicate)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }
    if (predicate == null)
    {
        throw new ArgumentNullException("predicate");
    }

    int count = 0;
    using (IEnumerator<T> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            T item = enumerator.Current;
            if (predicate(item)) count++; // The predicate is true
            if (count > value) break; // No further counting needed
        }
    }
    return count.CompareTo(value);
}

private static int CountCompareTo<T>(this IEnumerable<T> source, int value)
{
    if (source == null)
    {
        throw new ArgumentNullException("source");
    }

    var collectionT = source as ICollection<T>;
    if (collectionT != null)
    {
        return collectionT.Count.CompareTo(value);
    }
    var collection = source as ICollection;
    if (collection != null)
    {
        return collection.Count.CompareTo(value);
    }

    int count = 0;
    using (IEnumerator<T> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            count++;
            if (count > value) break; // Now you can draw a conclusion, with < it is actually 1 too much
        }
    }
    return count.CompareTo(value);
}

Comments (3) -

Frank Bakker Netherlands
5/27/2012 2:36:22 PM #

Hi Alex,

This indeed is handy to have around. I think you can reduce some redundant code by using 'pain old' Where() to filter in the overload with the predicate

private static int CountCompareTo<T>(this IEnumerable<T> source, int value, Func<T, bool> predicate)
{
    return source.where(predicate).CountCompareTo(source, value);
}

Regards Frank

Reply

Admin Netherlands
7/1/2012 3:58:33 PM #

Hi Frank,

Thanks for your suggestion. This saves a lot of code. Less code means less errors, less maintenance...
I will update the production code ald leave this this post as posted.

Regards,

Alex

Reply

Marleen Seidner United States
9/2/2013 5:41:51 PM #

Wohh exactly what I was looking for, thank you for putting up.

Reply

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

I am a software architect at Roxit and also a C# Developer. My main interests in the area of ​​C# are LINQ and generics

Visit my personal homepage (Dutch) for more info about me.

Month List

Page List