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. :)