public static IEnumerable<T> WherePrevious<T>(this IEnumerable<T> collection, Func<T, T, bool> predicate) {
if (collection == null) throw new ArgumentNullException(nameof(collection));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
if(!collection.Any()) yield break;
yield return collection.First();
var items = collection
.Zip(collection.Skip(1), (previous, item) => (previous, item))
.Where(zip => predicate(zip.previous, zip.item))
.Select(zip => zip.item);
foreach(var item in items)
yield return item;
}
[TestClass]
public class FilterTest {
[TestMethod]
public void WherePreviousTest() {
//Arrange
var numbers = new[] { 1, 5, 8, 7, 12, 8, 5 };
var expected = new[] { 1, 5, 8, 12 };
//Act
var actual = numbers.WherePrevious((first, second) => second > first).ToArray();
//Assert
actual.ShouldAllBeEquivalentTo(expected);
}
}
public static IEnumerable<T> WherePrevious<T>(this IEnumerable<T> collection, Func<T, T, bool> predicate) {
if (collection == null) throw new ArgumentNullException(nameof(collection));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
return WherePreviousIterator(collection, predicate);
}
private static IEnumerable<T> WherePreviousIterator<T>(IEnumerable<T> collection, Func<T, T, bool> predicate) {
using (var e = collection.GetEnumerator()) {
if (e.MoveNext()) {
var previous = e.Current;
yield return previous;
while (e.MoveNext()) {
var item = e.Current;
if (predicate(previous, item))
yield return item;
previous = item;
}
}
yield break;
}
}