将类似 LINQ 的流畅查询链接在一起

我想构建一个流畅的 api 来迭代一个数组,在这个数组中我过滤值并继续处理剩余的(不是过滤的)值。像这样的伪代码:


int[] input = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

from a in Take(3) // a = {5,4,1}

from b in Skip(4) // b = null

from c in TakeWhile(x=> x != 0) // c = {7, 2}

select new Stuff(a, b, c)

我不知道从哪里开始寻找,这样的事情的基础是什么。所以我想寻求一些帮助。


系统不应该局限于 int 数字..另一个例子:


string[] input = { "how", "are", "you", "doing", "?" };

from a in OneOf("how", "what", "where") // a = "how"

from b in Match("are") // b = "are"

from c in TakeWhile(x=> x != "?") // c = { "you", "doing" }

select new Stuff(a, b, c)


湖上湖
浏览 126回答 1
1回答

红颜莎娜

以下代码将允许您获取input.FirstTake(3).ThenSkip(4).ThenTakeWhile(x => x != 0);序列 5、4、1、7、2。主要思想是您需要跟踪您想要执行的拍摄和跳过,以便在您迭代时应用它们。这类似于如何OrderBy工作ThenBy。请注意,您不能在两者之间执行其他 Linq 操作。这构建了一个连续跳过和获取的枚举,然后该序列将通过您执行的任何 Linq 操作提供。public interface ITakeAndSkip<out T> : IEnumerable<T>{&nbsp; &nbsp; ITakeAndSkip<T> ThenSkip(int number);&nbsp; &nbsp; ITakeAndSkip<T> ThenTake(int number);&nbsp; &nbsp; ITakeAndSkip<T> ThenTakeWhile(Func<T, bool> predicate);&nbsp; &nbsp; ITakeAndSkip<T> ThenSkipWhile(Func<T, bool> predicate);}public class TakeAndSkip<T> : ITakeAndSkip<T>{&nbsp; &nbsp; private readonly IEnumerable<T> _source;&nbsp; &nbsp; private class TakeOrSkipOperation&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public bool IsSkip { get; private set; }&nbsp; &nbsp; &nbsp; &nbsp; public Func<T, bool> Predicate { get; private set; }&nbsp; &nbsp; &nbsp; &nbsp; public int Number { get; private set; }&nbsp; &nbsp; &nbsp; &nbsp; private TakeOrSkipOperation()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public static TakeOrSkipOperation Skip(int number)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new TakeOrSkipOperation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IsSkip = true,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Number = number&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public static TakeOrSkipOperation Take(int number)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new TakeOrSkipOperation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Number = number&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public static TakeOrSkipOperation SkipWhile(Func<T, bool> predicate)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new TakeOrSkipOperation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IsSkip = true,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Predicate = predicate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public static TakeOrSkipOperation TakeWhile(Func<T, bool> predicate)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new TakeOrSkipOperation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Predicate = predicate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; private readonly List<TakeOrSkipOperation> _operations = new List<TakeOrSkipOperation>();&nbsp; &nbsp; public TakeAndSkip(IEnumerable<T> source)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _source = source;&nbsp; &nbsp; }&nbsp; &nbsp; public IEnumerator<T> GetEnumerator()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; using (var enumerator = _source.GetEnumerator())&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // move to the first item and if there are none just return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!enumerator.MoveNext()) yield break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Then apply all the skip and take operations&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; foreach (var operation in _operations)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int n = operation.Number;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If we are not dealing with a while then make the predicate count&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // down the number to zero.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var predicate = operation.Predicate ?? (x => n-- > 0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Iterate the items until there are no more or the predicate is false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bool more = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (more && predicate(enumerator.Current))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If this is a Take then yield the current item.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!operation.IsSkip) yield return enumerator.Current;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; more = enumerator.MoveNext();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If there are no more items return&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!more) yield break;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Now we need to decide what to do with the rest of the items.&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // If there are no operations or the last one was a skip then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // return the remaining items&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (_operations.Count == 0 || _operations.Last().IsSkip)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; do&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; yield return enumerator.Current;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } while (enumerator.MoveNext());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Otherwise the last operation was a take and we're done.&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; IEnumerator IEnumerable.GetEnumerator()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return GetEnumerator();&nbsp; &nbsp; }&nbsp; &nbsp; public ITakeAndSkip<T> ThenSkip(int number)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _operations.Add(TakeOrSkipOperation.Skip(number));&nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; }&nbsp; &nbsp; public ITakeAndSkip<T> ThenSkipWhile(Func<T, bool> predicate)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _operations.Add(TakeOrSkipOperation.SkipWhile(predicate));&nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; }&nbsp; &nbsp; public ITakeAndSkip<T> ThenTake(int number)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _operations.Add(TakeOrSkipOperation.Take(number));&nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; }&nbsp; &nbsp; public ITakeAndSkip<T> ThenTakeWhile(Func<T, bool> predicate)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; _operations.Add(TakeOrSkipOperation.TakeWhile(predicate));&nbsp; &nbsp; &nbsp; &nbsp; return this;&nbsp; &nbsp; }}public static class TakeAndSkipExtensions{&nbsp; &nbsp; public static ITakeAndSkip<T> FirstTake<T>(this IEnumerable<T> source, int number)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new TakeAndSkip<T>(source).ThenTake(number);&nbsp; &nbsp; }&nbsp; &nbsp; public static ITakeAndSkip<T> FirstSkip<T>(this IEnumerable<T> source, int number)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new TakeAndSkip<T>(source).ThenSkip(number);&nbsp; &nbsp; }&nbsp; &nbsp; public static ITakeAndSkip<T> FirstTakeWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new TakeAndSkip<T>(source).ThenTakeWhile(predicate);&nbsp; &nbsp; }&nbsp; &nbsp; public static ITakeAndSkip<T> FirstSkipWhile<T>(this IEnumerable<T> source, Func<T, bool> predicate)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return new TakeAndSkip<T>(source).ThenSkipWhile(predicate);&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP