StringJoin
Note: This version uses an overload of String.Join that is only available in .NET 4.0.
public static String StringJoin<T>(this IEnumerable<T> ie, String sep)
{
return String.Join(sep, ie as IEnumerable<String> ?? ie.Select(e => e.ToString()));
}
WhereSelect
Often you need to project only elements that meet a certain criteria. This extension implements Where(filter-lambda).Select(selector-lambda)
in a single operation.
public static IEnumerable<TResult> WhereSelect<TSrc, TResult>(this IEnumerable<TSrc> ie,
Predicate<TSrc> filter,
Converter<TSrc, TResult> selector)
{
foreach (TSrc t in ie)
if (filter(t))
yield return selector(t);
}
Append or Exclude a single element
public static IEnumerable<T> Append<T>(this IEnumerable<T> ie, T element)
{
foreach (T t in ie)
yield return t;
yield return element;
}
public static IEnumerable<T> Exclude<T>(this IEnumerable<T> ie, T element)
{
foreach (T t in ie)
if (!t.Equals(element))
yield return t;
}
ArgMin, ArgMax, IndexOfMin, IndexOfMax
Returns the element at, or index of, the maximum (or minimum) value in the sequence. These do
not call the converter function if the sequence has only one element. If there is more than one instance of the
maximum value, the index of the first is returned. If the sequence is empty, an exception is thrown, since there
can be no concept of a maximum (or minimum) value.
public static TSrc ArgMax<TSrc, TArg>(this IEnumerable<TSrc> ie, Converter<TSrc, TArg> fn)
where TArg : IComparable<TArg>
{
IEnumerator<TSrc> e = ie.GetEnumerator();
if (!e.MoveNext())
throw new InvalidOperationException("Sequence has no elements.");
TSrc t_try, t = e.Current;
if (!e.MoveNext())
return t;
TArg v, max_val = fn(t);
do
{
if ((v = fn(t_try = e.Current)).CompareTo(max_val) > 0)
{
t = t_try;
max_val = v;
}
}
while (e.MoveNext());
return t;
}
public static TSrc ArgMin<TSrc, TArg>(this IEnumerable<TSrc> ie, Converter<TSrc, TArg> fn)
where TArg : IComparable<TArg>
{
IEnumerator<TSrc> e = ie.GetEnumerator();
if (!e.MoveNext())
throw new InvalidOperationException("Sequence has no elements.");
TSrc t_try, t = e.Current;
if (!e.MoveNext())
return t;
TArg v, min_val = fn(t);
do
{
if ((v = fn(t_try = e.Current)).CompareTo(min_val) < 0)
{
t = t_try;
min_val = v;
}
}
while (e.MoveNext());
return t;
}
public static int IndexOfMax<TSrc, TArg>(this IEnumerable<TSrc> ie, Converter<TSrc, TArg> fn)
where TArg : IComparable<TArg>
{
IEnumerator<TSrc> e = ie.GetEnumerator();
if (!e.MoveNext())
return -1;
int max_ix = 0;
TSrc t = e.Current;
if (!e.MoveNext())
return max_ix;
TArg tx, max_val = fn(t);
int i = 1;
do
{
if ((tx = fn(e.Current)).CompareTo(max_val) > 0)
{
max_val = tx;
max_ix = i;
}
i++;
}
while (e.MoveNext());
return max_ix;
}
public static int IndexOfMin<TSrc, TArg>(this IEnumerable<TSrc> ie, Converter<TSrc, TArg> fn)
where TArg : IComparable<TArg>
{
IEnumerator<TSrc> e = ie.GetEnumerator();
if (!e.MoveNext())
return -1;
int min_ix = 0;
TSrc t = e.Current;
if (!e.MoveNext())
return min_ix;
TArg tx, min_val = fn(t);
int i = 1;
do
{
if ((tx = fn(e.Current)).CompareTo(min_val) < 0)
{
min_val = tx;
min_ix = i;
}
i++;
}
while (e.MoveNext());
return min_ix;
}
Pair off!
Linq extension method which pairs off elements of an IEnumerable<T>. If there's an odd element left over, it's ignored.
If you're using .NET 4.0, you can use the system-provided 'Zip' extension instead.
public static IEnumerable<KeyValuePair<T, T>> PairOff<T>(this IEnumerable<T> ie)
{
IEnumerator<T> e = ie.GetEnumerator();
while (e.MoveNext())
{
T first = e.Current;
if (e.MoveNext())
yield return new KeyValuePair<T, T>(first, e.Current);
}
}
GroupBy for Mono
The Mono implementation of the GroupBy Linq extension is very slow, especially when compared to the .NET version. Here is a
replacement extension method you can use as a workaround.
public class MyGrouping<TSrc,TKey> : List<TSrc>
{
public TKey Key;
public MyGrouping(TKey k) { Key = k; }
}
public static IEnumerable<MyGrouping<TSrc, TKey>> MyGroupBy<TSrc, TKey>(this IEnumerable<TSrc> ie, Converter<TSrc,TKey> fn)
{
Dictionary<TKey, MyGrouping<TSrc, TKey>> d = new Dictionary<TKey, MyGrouping<TSrc, TKey>>();
foreach (TSrc src in ie)
{
TKey k = fn(src);
MyGrouping<TSrc,TKey> l;
if (d.TryGetValue(k, out l))
l.Add(src);
else
d.Add(k, new MyGrouping<TSrc,TKey>(k) { src });
}
return d.Values;
}
Value compare for arrays
public static bool ValueCompare(this T[] a, T[] b) where T : struct
{
if (a.Length != b.Length)
return false;
EqualityComparer q = EqualityComparer.Default;
for (int i = 0; i < a.Length; i++)
if (!q.Equals(a[i], b[i]))
return false;
return true;
}
public static bool ValueCompare(this T[] a, int a_offset, T[] b) where T : struct
{
if (a_offset >= a.Length || a_offset + b.Length > a.Length)
return false;
EqualityComparer q = EqualityComparer.Default;
for (int i = 0; i < b.Length; i++, a_offset++)
if (!q.Equals(a[a_offset], b[i]))
return false;
return true;
}
Filter for non-null references (and non-default values)
public static IEnumerable NotDefault(this IEnumerable source)
{
return source.Where(e => !Object.Equals(e,default(T)));
}
public static IEnumerable NotDefault(this IEnumerable source, Converter selector)
{
return source.Where(e => !Object.Equals(selector(e),default(TAny)));
}
DateTime to UNIX epoch
public static int ToEpoch(this DateTime dt)
{
return (int)(dt - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
}