查找、分组和合并重叠的日期时间范围以确定“完整范围”

问题描述 投票:0回答:1

对一些术语表示歉意。这是一个很难解释的问题。

我正在尝试确定包含重复和重叠日期时间范围的记录的数据集中的实际时间。

下面是重复和重叠记录的测试数据集。

            var records = new List<Record>
            {
                new Record { Name = "Group1 - A", Start = new DateTime(2024, 1, 1, 9, 0, 0), End = new DateTime(2024, 1, 1, 10, 0, 0) },
                new Record { Name = "Group1 - B", Start = new DateTime(2024, 1, 1, 9, 30, 0), End = new DateTime(2024, 1, 1, 11, 0, 0) },
                new Record { Name = "Group1 - C", Start = new DateTime(2024, 1, 1, 10, 30, 0), End = new DateTime(2024, 1, 1, 12, 0, 0) },
                new Record { Name = "Group2 - D", Start = new DateTime(2024, 1, 1, 13, 0, 0), End = new DateTime(2024, 1, 1, 15, 0, 0) },
                new Record { Name = "Group3 - E", Start = new DateTime(2024, 1, 2, 22, 0, 0), End = new DateTime(2024, 1, 2, 23, 0, 0) },
                new Record { Name = "Group3 - F", Start = new DateTime(2024, 1, 2, 22, 30, 0), End = new DateTime(2024, 1, 3, 5, 0, 0) }
            };

我期待以上记录合并到以下三个结果中。其中“开始”是分组记录的最小开始日期时间,“结束”是组记录的最大结束日期时间。

第 1 组 – 开始:2023 年 1 月 1 日上午 9 点,结束:2023 年 1 月 1 日中午 12 点
第 2 组 - 开始:2023 年 1 月 1 日下午 1 点,结束:2023 年 1 月 1 日下午 3 点
第 3 组 - 开始:2023 年 2 月 1 日晚上 10 点,结束:2023 年 2 月 1 日上午 5 点

我一直在尝试使用 group by 进行各种 LINQ 查询,但我没有取得任何进展。

可以使用 LINQ 解决这个问题吗?

在任何人询问之前,解决方案最好是 LINQ 查询,因为这是传递到规则引擎的内容。

c# linq lambda
1个回答
0
投票

我怀疑您是否可以通过一个简单的 Linq 查询来解决问题;您可以使用简单的滑动窗口算法来代替:

private static IEnumerable<(TItem left, TItem right)> MyGroups<TSource, TItem>(
  IEnumerable<TSource> source, 
  Func<TSource, TItem> start, 
  Func<TSource, TItem> stop, 
  IComparer<TItem> comparer = default) {
  comparer = comparer ?? Comparer<TItem>.Default;

  var ordered = source
    .Where(item => comparer.Compare(start(item), stop(item)) <= 0)
    .OrderBy(item => start(item));

  TItem left = default;
  TItem right = default;
  bool hasRange = false;

  foreach (var item in ordered) {
    var currentLeft = start(item);
    var currentRight = stop(item);

    if (!hasRange) {
      left = currentLeft;
      right = currentRight;
      hasRange = true;
    }
    else if (comparer.Compare(right, currentLeft) >= 0) {
      right = comparer.Compare(right, currentRight) >= 0 ? right : currentRight;
      hasRange = true;
    }
    else {
      yield return (left, right);

      left = currentLeft;
      right = currentRight;
    }
  }

  if (hasRange)
    yield return (left, right);
}

然后

var records = new List<Record> { ... }

var result = MyGroups(records, rec => rec.Start, rec => rec.End);

var report = string.Join(Environment.NewLine, result
  .Select((item, index) => $"Group {index + 1} - Start: {item.left:d/M/yyyy htt}, End: {item.right:d/M/yyyy htt}"));

Console.WriteLine(report);

输出:

Group 1 - Start: 1/1/2024 9AM, End: 1/1/2024 12PM
Group 2 - Start: 1/1/2024 1PM, End: 1/1/2024 3PM
Group 3 - Start: 2/1/2024 10PM, End: 3/1/2024 5AM
© www.soinside.com 2019 - 2024. All rights reserved.