Omer van Kloeten's .NET Zen

Programming is life, the rest is mere details

News

Note: This blog has moved to omervk.wordpress.com.

Omer van Kloeten's Facebook profile

Omer has been professionally developing applications over the past 8 years, both at the IDF’s IT corps and later at the Sela Technology Center, but has had the programming bug ever since he can remember himself.
As a senior developer at NuConomy, a leading web analytics and advertising startup, he leads a wide range of technologies for its flagship products.

Get Firefox


powered by Dapper 

.NET Resources

Articles :: CodeDom

Articles :: nGineer

Culture

Projects

Extension Methods Roundup: IndicesWhere, TakeEvery, Distinct

As I do from time to time, here is a batch of three Extension Methods I've written recently:

IndicesWhere

/// <summary>
/// Gets the indices where the predicate is true.
/// </summary>
public static IEnumerable<int> IndicesWhere<T>(this IEnumerable<T> enumeration, Func<T, bool> predicate)
{
    // Check to see that enumeration is not null
    if (enumeration == null)
        throw new ArgumentNullException("enumeration");

    // Check to see that predicate is not null
    if (predicate == null)
        throw new ArgumentNullException("predicate");

    int index = 0;

    foreach (T item in enumeration)
    {
        if (predicate(item))
            yield return index;

        index++;
    }
}

This is especially useful when you want to cache indices from an array, rather than the array itself. Here's an example:

var indicesWithValues = values.IndicesWhere(value => value != null);

TakeEvery

/// <summary>
/// Take items from 'startAt' every at 'hopLength' items.
/// </summary>
public static IEnumerable<T> TakeEvery<T>(this IEnumerable<T> enumeration, int startAt, int hopLength)
{
    // Check to see that enumeration is not null
    if (enumeration == null)
        throw new ArgumentNullException("enumeration");

    int first = 0;
    int count = 0;

    foreach (T item in enumeration)
    {
        if (first < startAt)
        {
            first++;
        }
        else if (first == startAt)
        {
            yield return item;

            first++;
        }
        else
        {
            count++;

            if (count == hopLength)
            {
                yield return item;

                count = 0;
            }
        }
    }
}

This is equivalent to an unbounded series of Skip(startAt).Take(1).Skip(hopLength).Take(1).Skip(hopLength)... Useful for when you, for instance, need only every other item in a list.

Distinct

It's really been pissing me off that there's no overload to Distinct that takes a delegate, which means I have to write a new class whenever my comparison isn't the default one. When talking about Anonymous Types, Distinct becomes useless. So here's an overload I can actually use:

private class EqualityComparer<T> : IEqualityComparer<T>
{
    public Func<T, T, bool> Comparer { get; internal set; }
    public Func<T, int> Hasher { get; internal set; }

    bool IEqualityComparer<T>.Equals(T x, T y)
    {
        return this.Comparer(x, y);
    }

    int IEqualityComparer<T>.GetHashCode(T obj)
    {
        // No hashing capabilities. Default to Equals(x, y).
        if (this.Hasher == null)
            return 0;

        return this.Hasher(obj);
    }
}

/// <summary>
/// Gets distinct items by a comparer delegate.
/// </summary>
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> enumeration, Func<T, T, bool> comparer)
{
    return Distinct(enumeration, comparer, null);
}

/// <summary>
/// Gets distinct items by comparer and hasher delegates (faster than only comparer).
/// </summary>
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> enumeration, Func<T, T, bool> comparer, Func<T, int> hasher)
{
    // Check to see that enumeration is not null
    if (enumeration == null)
        throw new ArgumentNullException("enumeration");

    // Check to see that comparer is not null
    if (comparer == null)
        throw new ArgumentNullException("comparer");

    return enumeration.Distinct(new EqualityComparer<T> { Comparer = comparer, Hasher = hasher });
}

I'll be integrating these methods into the Linq Extensions project soon enough. Good hunting. :)

Comments

No Comments