如何在LINQ中对范围进行分组 [英] How to group ranges in LINQ

查看:184
本文介绍了如何在LINQ中对范围进行分组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我要分组的数据.

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且结果会是

Because I have 18 - 19 and 20 - 24. I would add these two together as 18 - 24. In this case the rule is (a, b) => b.start - a.end = 1 and the result would be

Start      End
  18        24
  2         9
  26        30

编辑在下面的每个注释中添加了最后一个结果行.

EDIT added last result row per comments below.

推荐答案

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

So we'll start with a helper method called GroupWhile. It will be provided with a predicate accepting two items from the sequence, the previous and the current. If that predicate returns true, the current item goes into the same group as the previous item. If not, it starts a new group.

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;
    }
}

有了这个选项,我们可以按开始顺序对项目进行排序,然后按结束日期将其分组,同时上一个范围的结束与下一个范围的开始重叠,然后根据组的开始将每个组折叠到新的范围和最终值.

Once we have this we can order the items by the start, then by the end date, group them while the previous range's end overlaps with the next range's start, and then collapse each group into a new range based on the groups start and end values.

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(),
    });

这篇关于如何在LINQ中对范围进行分组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆