From time to time we run into tasks that we would like to solve in LINQ style but unfortunately it either cannot be done or a solution is not efficient.
Note that by LINQ style we do not mean C# query expressions (we have a strong distaste for that syntax) but extension methods defined in System.Linq.Enumerable and other classes.
System.Linq.Enumerable
Here we quote several extension methods that are good for a general use:
1. Select with predicate. This is shorthand of items.Where(...).Select(...):
items.Where(...).Select(...)
/// <summary> /// Projects each element of a sequence into a new form. /// </summary> /// <typeparam name="T">A type of elements of source sequence.</typeparam> /// <typeparam name="R">A type of elements of target sequence.</typeparam> /// <param name="source">A source sequence.</param> /// <param name="where">A predicate to filter elements.</param> /// <param name="selector">A result element selector.</param> /// <returns>A target sequence.</returns> public static IEnumerable<R> Select<T, R>( this IEnumerable<T> source, Func<T, bool> where, Func<T, R> selector) { return source.Where(where).Select(selector); }
2. Select with predicate with source element index passed both into the predicate and into the selector. This one you cannot trivially implement in LINQ:
/// <summary> /// Projects each element of a sequence into a new form. /// </summary> /// <typeparam name="T">A type of elements of source sequence.</typeparam> /// <typeparam name="R">A type of elements of target sequence.</typeparam> /// <param name="source">A source sequence.</param> /// <param name="where">A predicate to filter elements.</param> /// <param name="selector">A result element selector.</param> /// <returns>A target sequence.</returns> public static IEnumerable<R> Select<T, R>( this IEnumerable<T> source, Func<T, int, bool> where, Func<T, int, R> selector) { var index = 0; foreach(var value in source) { if (where(value, index)) { yield return selector(value, index); } ++index; } }
3. A function with output element as projection of a window of input elements. Such function can be used to get finite difference (operation opposite to a cumulative sum).
/// <summary> /// Projects a window of source elements in a source sequence into target sequence. /// Thus /// target[i] = /// selector(source[i], source[i - 1], ... source[i - window + 1]) /// </summary> /// <typeparam name="T">A type of elements of source sequence.</typeparam> /// <typeparam name="R">A type of elements of target sequence.</typeparam> /// <param name="source">A source sequence.</param> /// <param name="window">A size of window.</param> /// <param name="lookbehind"> /// Indicate whether to produce target if the number of source elements /// preceeding the current is less than the window size. /// </param> /// <param name="lookahead"> /// Indicate whether to produce target if the number of source elements /// following current is less than the window size. /// </param> /// <param name="selector"> /// A selector that derives target element. /// On input it receives: /// an array of source elements stored in round-robing fashon; /// an index of the first element; /// a number of elements in the array to count. /// </param> /// <returns>Returns a sequence of target elements.</returns> public static IEnumerable<R> Window<T, R>( this IEnumerable<T> source, int window, bool lookbehind, bool lookahead, Func<T[], int, int, R> selector) { var buffer = new T[window]; var index = 0; var count = 0; foreach(var value in source) { if (count < window) { buffer[count++] = value; if (lookbehind || (count == window)) { yield return selector(buffer, 0, count); } } else { buffer[index] = value; index = index + 1 == window ? 0 : index + 1; yield return selector(buffer, index, count); } } if (lookahead) { while(--count > 0) { index = index + 1 == window ? 0 : index + 1; yield return selector(buffer, index, count); } } }
This way a finite difference looks like this:
var diff = input.Window( 2, false, false, (buffer, index, count) => buffer[index ^ 1] - buffer[index]);
4. A specialization of Window method that returns a enumeration of windows:
Window
/// <summary> /// Projects a window of source elements in a source sequence into a /// sequence of window arrays. /// </summary> /// <typeparam name="T">A type of elements of source sequence.</typeparam> /// <typeparam name="R">A type of elements of target sequence.</typeparam> /// <param name="source">A source sequence.</param> /// <param name="window">A size of window.</param> /// <param name="lookbehind"> /// Indicate whether to produce target if the number of source elements /// preceeding the current is less than the window size. /// </param> /// <param name="lookahead"> /// Indicate whether to produce target if the number of source elements /// following current is less than the window size. /// </param> /// <returns>Returns a sequence of windows.</returns> public static IEnumerable<T[]> Window<T>( this IEnumerable<T> source, int window, bool lookbehind, bool lookahead) { return source.Window( window, lookbehind, lookahead, (buffer, index, count) => { var result = new T[count]; for(var i = 0; i < count; ++i) { result[i] = buffer[index]; index = index + 1 == buffer.Length ? 0 : index + 1; } return result; }); }
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u