【问题标题】:Merge list elements if date differs by one day如果日期相差一天,则合并列表元素
【发布时间】:2023-03-14 12:22:01
【问题描述】:

我有一个看起来像这样的列表。如果日期相隔 1 天(“2022,01,01”和“2022,01,02”),我需要合并此列表元素,它们的费率、roomTypeId 和 Accessibility 完全相同。DateFrom 和 DateTo 始终相同在我给出的列表中,每个可用性代表一天。

             new Availability
            {
                Accessibility = 1,
                RoomTypeId = "12345",
                Rate = 50,
                DateFrom = new DateTime(2022, 01, 01),
                DateTo = new DateTime(2022, 01, 01)
            },
                new Availability
            {
                Accessibility = 1,
                RoomTypeId = "12345",
                Rate = 50,
                DateFrom = new DateTime(2022, 01, 02),
                DateTo = new DateTime(2022, 01, 02)
            },
                new Availability
            {
                Accessibility = 1,
                RoomTypeId = "12345",
                Rate = 100,
                DateFrom = new DateTime(2022, 01, 04),
                DateTo = new DateTime(2022, 01, 04)
            },
                new Availability
            {
                Accessibility = 6,
                RoomTypeId = "12345",
                Rate = 100,
                DateFrom = new DateTime(2022, 01, 05),
                DateTo = new DateTime(2022, 01, 05)
            },
                new Availability
            {
                Accessibility = 6,
                RoomTypeId = "12345",
                Rate = 100,
                DateFrom = new DateTime(2022, 01, 6),
                DateTo = new DateTime(2022, 01, 06)
            },

结果应该是这样的:

             new Availability
            {
                Accessibility = 1,
                RoomTypeId = "12345",
                Rate = 50,
                DateFrom = new DateTime(2022, 01, 01),
                DateTo = new DateTime(2022, 01, 02)
            },
                new Availability
            {
                Accessibility = 1,
                RoomTypeId = "12345",
                Rate = 100,
                DateFrom = new DateTime(2022, 01, 04), <- missing (2002, 01, 03) so it should crate a new group
                DateTo = new DateTime(2022, 01, 04)
            },
                new Availability
            {
                Accessibility = 6, <- different
                RoomTypeId = "12345",
                Rate = 100,
                DateFrom = new DateTime(2022, 01, 05),
                DateTo = new DateTime(2022, 01, 06)
            }

我怎样才能以最优化的方式做到这一点?我尝试按 RoomTypeId 对列表进行分组,按日期排序并将日期与以前的元素进行比较,但还没有。

【问题讨论】:

  • 如果连续几天获得超过 2 条 Availability 记录,应该将它们合并为一条,还是只合并一对?例如。如果您收到Availability 的相同可访问性、房间 ID 和房价,但日期为 Jan-05、Jan-06 和 Jan-07,则结果应该有一条从 Jan-05 到 Jan-07 的记录,还是两条记录,一份用于 Jan-05 至 Jan-06,另一份仅用于 Jan-07?

标签: c# linq


【解决方案1】:

这有点脏,但可以提供帮助!您可以跳过不感兴趣的元素,同时保留一些标志元素。而且它只是一个枚举,所以 O(n) 复杂度

public static IEnumerable<Availability> GetMerged(List<Availability> oldList)
{
    var oldValue = oldList[0];
    foreach (var currentValue in oldList)
    {
        if (IsDifferent(oldValue, currentValue))
        {
            yield return oldValue;
            oldValue = currentValue;
        }
    }

    yield return oldValue;
}

public static bool IsDifferent(Availability x, Availability y)
{
    if (x.Accessibility != y.Accessibility || x.Rate != y.Rate || x.RoomTypeId != y.RoomTypeId)
        return true;
    if (Math.Abs((x.DateFrom - x.DateTo).TotalDays) > 1) 
        return true;

    return false;
}

您也可以按方法和覆盖自定义比较器来使用 LINQ 组,但您应该选择正确的自定义 GetHashCode 函数,我现在发现这很困难。

【讨论】:

    【解决方案2】:

    如果您安装 Nuget 包 MoreLINQ,您可以使用 Segment() 方法:

    var mergedAvails = avails
        .GroupBy(x => new { x.RoomTypeId, x.Rate, x.Accessibility })
        .SelectMany(groupedAvails => groupedAvails
            .OrderBy(avail => avail.DateFrom)
            .Segment((curr, prev, _) => prev.DateTo.AddDays(1) != curr.DateFrom)
            .Select(consecutiveAvails => new Availability {
                Accessibility = consecutiveAvails.First().Accessibility,
                RoomTypeId = consecutiveAvails.First().RoomTypeId,
                Rate = consecutiveAvails.First().Rate,
                DateFrom = consecutiveAvails.First().DateFrom,
                DateTo = consecutiveAvails.Last().DateTo
            }));
    

    一般的想法是,您首先按您指定的属性对所有项目进行分组,然后按日期对每个组中的项目进行排序。然后Segement() 会将每个组拆分为子组,其中每个子组仅包含连续天数的项目。

    我没有对其进行测试,但该代码也应该适用于跨越多天而不是仅仅一天的项目(只要不同项目之间的日期范围不重叠)。

    顺便说一句,我也为旅游业工作,我们在 C# 软件的某些地方也是这样做的 ^^

    工作示例:https://dotnetfiddle.net/XVkOZD

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-05
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-20
      • 2020-03-16
      相关资源
      最近更新 更多