CSharp · Console
using System;
using System.Linq;
using static MoreLinq.Extensions.GroupAdjacentExtension;
using static MoreLinq.Extensions.ScanRightExtension;
using static MoreLinq.Extensions.WindowRightExtension;
using static MoreLinq.Extensions.ForEachExtension;
var items = new[] {
new {
Id = 1,
Quantity = 1,
StartDate = DateTime.Parse("2021-03-10"),
EndDate = DateTime.Parse("2021-03-21")
},
new {
Id = 2,
Quantity = 1,
StartDate = DateTime.Parse("2021-03-10"),
EndDate = DateTime.Parse("2021-03-21")
},
new {
Id = 3,
Quantity = 2,
StartDate = DateTime.Parse("2021-03-10"),
EndDate = DateTime.Parse("2021-03-23")
},
new {
Id = 4,
Quantity = 1,
StartDate = DateTime.Parse("2021-03-10"),
EndDate = DateTime.Parse("2021-03-25")
}
};
items
// aggregate identical end dates
.GroupAdjacent(x => x.EndDate)
.Select(xs => xs.Aggregate(
new {
Ids = Enumerable.Empty<int>(),
Quantity = 0,
StartDate = default(DateTime),
EndDate = default(DateTime)
},
(acc, curr) => new {
Ids = acc.Ids.Append(curr.Id),
Quantity = acc.Quantity + curr.Quantity,
curr.StartDate,
curr.EndDate
}))
// cut-off overlapping start dates
.WindowRight(2)
.Select(win => win.Count == 1
? win[0]
: new {
win[1].Ids,
win[1].Quantity,
StartDate = win[0].EndDate.AddDays(1),
win[1].EndDate
})
// accumulate IDs and quantities
.ScanRight((curr, prev) => new {
Ids = curr.Ids.Concat(prev.Ids),
Quantity = curr.Quantity + prev.Quantity,
curr.StartDate,
curr.EndDate
})
// print
.Select(x => $"{{ Ids: [{string.Join(',', x.Ids)}], Quantity: {x.Quantity}, StartDate: {x.StartDate.ToShortDateString()}, EndDate: {x.EndDate.ToShortDateString()} }}")
.ForEach(x => Console.WriteLine(x));