score:1

Accepted answer

That is somewhat dirty but can help! You can just skip elements that you're not interested in while keeping some flag element. And it's only one enumeration, so O(n) complexity

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

You can also go by LINQ group by method and by overriding custom comparer, but you should pick right and custom GetHashCode function and i've found that difficult for now.

score:1

If you install the Nuget package MoreLINQ you can use the Segment() method for that:

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

The general idea is that you first group all items by the properties you specified and then order the items in each group by date. Segement() will then split each group into sub-groups where each sub-group only contains items with consecutive days.

I didn't test it, but the code should also work for items that span multiple days instead of just one (as long as the date ranges don't overlap between different items).

By the way, I also work for the tourism industry and we do the same in some places of our C# software ^^

Working example: https://dotnetfiddle.net/XVkOZD


Related Articles