是否有更好的方法来获取每个项与谓词匹配的子序列?
说我有一个IEnumerable。 例如,{2,1,42,0,9,6,5,3,8}。
我需要获得与谓词匹配的项目的“运行”。 例如,如果我的谓词是
bool isSmallerThanSix(int number){...}
我想获得以下输出:{{2,1},{0},{5,3}}
是否有内置function可以实现这一目标?
到目前为止我有这个:
public static IEnumerable<IEnumerable> GetSequences(this IEnumerable source, Func selector) { if (source == null || selector == null) { yield break; } IEnumerable rest = source.SkipWhile(obj => !selector(obj)); while (rest.Count() > 0) { yield return rest.TakeWhile(obj => selector(obj)); rest = rest .SkipWhile(obj => selector(obj)) .SkipWhile(obj => !selector(obj)); } }
这看起来很有效,但是我在半夜写的,因此从星期二开始效率低十五。 是否有更好的,最好是内置(因此经过良好测试)的方式?
非常感谢你们的时间,
利雅。
据我所知,没有一种构建方法。 但是,在IEnumerable
上调用Count
扩展方法效率不高,因为它必须枚举列表以获取计数。 因此,我想出了具有相同效果的这一点。
public static IEnumerable> GetSequences(this IEnumerable source, Func selector) { // omitted null checks for brevity var list = new List (); foreach(var item in source) { if (selector.Invoke(item)) { list.Add(item); } else if (list.Count > 0) { yield return list; list = new List (); } } if (list.Count > 0) yield return list; }
正如Jon Skeet所提到的,在这种情况下使用SkipWhile
和TakeWhile
似乎效率很低,因为它们会在迭代器上的迭代器上创建迭代器。 您可以在调试示例时将其检查出来,当您逐步尝试查找下一个序列时它会变得有点疯狂,即使示例很简单也是如此。
我怀疑你的代码在所有情况下都不会真正起作用。 特别是,SkipWhile和TakeWhile被懒惰地评估 – 如果调用代码实际上没有读取所有产生的IEnumerable
(或者更糟糕的是,缓冲它们并以不同的顺序读取它们!)我强烈怀疑你’会得到错误的结果。
我怀疑你真的需要这样做:
public static IEnumerable> GetSequences( this IEnumerable source, Func selector) { List current = new List (); foreach (T element in source) { if (selector(element)) { current.Add(element); } else if (current.Count > 0) { yield return current; current = new List (); } } if (current.Count > 0) { yield return current; } }
(这忽略了错误检查 – 由于迭代器块的延迟执行,您希望在一个单独的方法中执行此操作,然后将此方法作为私有方法调用 – 在编写生产质量迭代器块时,这是一种非常常见的模式。)
List
的选择有点武断,顺便说一下 – 你当然可以使用LinkedList
代替。 或者,如果您选择List,则可以返回IEnumerable
而不是IEnumerable
,这可以使调用者更容易处理结果。
不确定我知道我在说什么,但这不会阻止我说话……
定义一种新的迭代器类型是否有意义,它可以在当前完成时跳到下一个子序列?
使用Java和Integer示例语法,客户端代码如下所示:
Iterator2 iter = getSequencences(someCollection, someCriteria) while (iter.hasNextSequence()) { iter.nextSequence(); while (iter.hasNext()) { Integer i = iter.next(); } }
*鸭子*
通过直接与枚举器一起工作,可以产生完全延迟的结果。
我可能会使用Garry和Jon提供的版本,因为它更简单并完成工作,但这很有趣。
public static class Program { static IEnumerable> GetSequences(this IEnumerable source, Func selector) { var enumerator = source.GetEnumerator(); while (enumerator.MoveNext()) if (selector(enumerator.Current)) yield return TakeWhile(enumerator, selector); yield break; } static IEnumerable TakeWhile (IEnumerator enumerator, Func selector) { do { yield return enumerator.Current; } while (enumerator.MoveNext() && selector(enumerator.Current)); yield break; } static void Main() { var nums = new[] { 2, 1, 42, 0, 9, 6, 5, 3, 8 }; var seqs = nums.GetSequences(i => i < 6); Console.WriteLine(string.Join(",", seqs.Select(s => string.Format("{{{0}}}", string.Join(",", s.Select(i => i.ToString()).ToArray()) )).ToArray())); } }
您可以利用GroupBy将按顺序运行项目的事实。
public static IEnumerable> GetSequences (this IEnumerable source, Func predicate) { bool flag = false; int id = 0; return source.GroupBy(x => { bool match = predicate(x); if (match != flag) { id += 1; flag = match; } return new { keep = match, id = id }; }) .Where(g => g.Key.keep) .Select(g => g.AsEnumerable()); }
这是一种测试方法:
上述就是C#学习教程:是否有更好的方法来获取每个项与谓词匹配的子序列?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
public static void Test1() { List myList = new List () {2,1,42,0,9,6,5,3,8}; foreach (var g in myList.GetSequences(i => i < 6)) { Console.WriteLine("g"); foreach (int i in g) { Console.WriteLine(i); } } }
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/955547.html