Closed
Description
Consider adding sliding window operators (like Windowed
already) with left & right alignment. Sliding windows are typically used for statistics like calculating moving averages.
When left-aligned, a window of size N slides over the current and following N-1 elements.
When right-aligned, a window of size N slides over the current and preceding N-1 elements.
In both cases, partial windows should be returned when fewer than N elements (when N > 1) precede (right-aligned) or follow (left-aligned).
Here's a possible implementation:
static partial class MoreEnumerable
{
public static IEnumerable<IEnumerable<TSource>> WindowRight<TSource>(this IEnumerable<TSource> source, int size)
{
return source.WindowRight(size, (_, w) => w);
}
public static IEnumerable<TResult> WindowRight<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<TSource, IEnumerable<TSource>, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException("source");
if (size <= 0) throw new ArgumentOutOfRangeException("size");
return WindowRightImpl(source, size, resultSelector);
}
static IEnumerable<TResult> WindowRightImpl<TSource, TResult>(IEnumerable<TSource> source, int size, Func<TSource, IEnumerable<TSource>, TResult> resultSelector)
{
var window = new List<TSource>();
foreach (var item in source)
{
window.Add(item);
yield return resultSelector(item, window);
window = new List<TSource>(window.Count == size ? window.Skip(1) : window);
}
}
public static IEnumerable<IEnumerable<TSource>> WindowLeft<TSource>(this IEnumerable<TSource> source, int size)
{
return source.WindowLeft(size, (_, w) => w);
}
public static IEnumerable<TResult> WindowLeft<TSource, TResult>(this IEnumerable<TSource> source, int size, Func<TSource, IEnumerable<TSource>, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException("source");
if (size <= 0) throw new ArgumentOutOfRangeException("size");
return WindowLeftImpl(source, size, resultSelector);
}
static IEnumerable<TResult> WindowLeftImpl<TSource, TResult>(IEnumerable<TSource> source, int size, Func<TSource, IEnumerable<TSource>, TResult> resultSelector)
{
var window = new List<TSource>();
foreach (var item in source)
{
window.Add(item);
if (window.Count < size)
continue;
yield return resultSelector(window[0], window);
window = new List<TSource>(window.Skip(1));
}
while (window.Count > 0)
{
yield return resultSelector(window[0], window);
window = new List<TSource>(window.Skip(1));
}
}
}