/// <summary> /// Groups element into sub-lists of adjacent that share the same property, true or false, from the predicate. /// Basically performs edge detection in order to operate. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="elements"></param> /// <param name="predicate"></param> /// <returns></returns> public static IEnumerable <Tuple <IEnumerable <T>, bool> > ClusteredByPredicate <T>(this IEnumerable <T> elements, Func <T, bool> predicate) { // We'll build a list assigning numeric, so we can have true, false AND "added at the front" for edge detection purposes. var withTrueFalseAsOneZero = Alg.ReadPoint(elements.Select(x => Tuple.Create(x, predicate(x) ? 1 : 0))).TakenToEnd(); return(Alg.Map( (c, prior) => { var cf = c.First(); return Alg.When( cf.Item2 != prior.Item2, () => Tuple.Create(c.TakeWhile(x => x.Item2 == cf.Item2).Select(x => x.Item1), (cf.Item2 == 1))); }, withTrueFalseAsOneZero.Tails().Where(x => x.Any()), new[] { Tuple.Create(default(T), -1) }.Concat(withTrueFalseAsOneZero)).SelectMany(x => x.ToEnumerable())); }