c# - 如何在 LINQ 中对范围进行分组

标签 c# linq linq-to-objects

这是我要分组的数据。

Start      End
  2         4
  26        30
  5         9
  20        24
  18        19

因为我有 18 - 19 和 20 - 24。我会将这两个加在一起作为 18 - 24。在这种情况下,规则是 (a, b) => b.start - a.end = 1 和结果会是

Start      End
  18        24
  2         9
  26        30

EDIT 根据下面的评论添加了最后的结果行。

最佳答案

因此,我们将从名为 GroupWhile 的辅助方法开始。它将提供一个谓词,该谓词接受序列中的两个项目,前一个和当前。如果该谓词返回 true,则当前项目与前一个项目进入同一组。如果没有,它会启动一个新组。

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate)
{
    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())
            yield break;

        List<T> list = new List<T>() { iterator.Current };

        T previous = iterator.Current;

        while (iterator.MoveNext())
        {
            if (!predicate(previous, iterator.Current))
            {
                yield return list;
                list = new List<T>();
            }

            list.Add(iterator.Current);
            previous = iterator.Current;
        }
        yield return list;
    }
}

一旦我们有了这个,我们就可以按开始日期排序项目,然后按结束日期排序,在前一个范围的结束与下一个范围的开始重叠时对它们进行分组,然后根据组开始将每个组折叠到一个新范围中和最终值(value)。

var collapsedRanges = ranges.OrderBy(range => range.Start)
    .ThenBy(range => range.End)
    .GroupWhile((prev, cur) => prev.End + 1 >= cur.Start)
    .Select(group => new Range()
    {
        Start = group.First().Start,
        End = group.Select(range => range.End).Max(),
    });

关于c# - 如何在 LINQ 中对范围进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22255438/

相关文章:

c# - 屏幕录制单个窗口

c# - 如何以原子方式释放一个锁并获取另一个锁

c# - 如何检查安装的实例是完整的 SQL Server 还是只是 SQL Server Express

c# - 如何使用 linq 扩展方法执行左外连接

c# - FakeItEasy 不验证完整框架 SignalR 测试的调用

c# - 从 Linq 编译查询返回 KeyValuePair

c# - 在 asp.net mvc 的同一 View 中列出和创建

c# - 使用 linq 从 IEnumerable 中排除类型

performance - 为什么使用 Linq To Objects 时 IQueryable 比 IEnumerable 快两倍

c# - LINQ 查询以检测对象列表中的重复属性