如何实现分组集合中accumulatedMaxPax的累积求和并按Destination重置?
问题
需求为计算分组集合的累积和,规则如下:
accumulatedMaxPax等于前一个accumulatedMaxPax值加上当前maxPax- 每次
destinations变更时重置为0
预期结果示例
[ { "date": "2022-05-06", "destinations": [ { "id": 1, "description": "PAXOS - ANTIPAXOS", "abbreviation": "PA", "ports": [ { "id": 1, "description": "CORFU PORT", "maxPax": 200, "accumulatedMaxPax": 200 // Initial (accumulatedMaxPax = maxPax ) }, { "id": 4, "description": "BENITSES PORT", "maxPax": 200, "accumulatedMaxPax": 400 // 200 (previous) + 200 (current) = 400 }, { "id": 17, "description": "BOUKARI PORT", "maxPax": 100, "accumulatedMaxPax": 500 // 400 (previous) + 100 (current) = 500 }, { "id": 2, "description": "LEFKIMMI PORT", "maxPax": 400, "accumulatedMaxPax": 900 // 500 (previous) + 400 (current) = 900 } ] }, { "id": 3, "description": "BLUE LAGOON", "abbreviation": "BL", "ports": [ { "id": 1, "description": "CORFU PORT", "maxPax": 215, "accumulatedMaxPax": 215 }, { "id": 4, "description": "BENITSES PORT", "maxPax": 215, "accumulatedMaxPax": 430 } ] }, { "id": 7, "description": "PARTY", "abbreviation": "PRT", "ports": [ { "id": 1, "description": "CORFU PORT", "maxPax": 200, "accumulatedMaxPax": 200 } ] } ] } ]
现有待补全代码
public IEnumerable<AvailabilityCalendarGroupVM> GetForCalendar(string fromDate, string toDate) { return context.Schedules .Where(x => x.Date >= Convert.ToDateTime(fromDate) && x.Date <= Convert.ToDateTime(toDate)) .GroupBy(x => x.Date) .Select(x => new AvailabilityCalendarGroupVM { Date = DateHelpers.DateTimeToISOString(x.Key.Date), Destinations = x.GroupBy(x => new { x.Date, x.Destination.Id, x.Destination.Description, x.Destination.Abbreviation }).Select(x => new DestinationCalendarVM { Id = x.Key.Id, Description = x.Key.Description, Abbreviation = x.Key.Abbreviation, Ports = x.GroupBy(x => new { x.PortId, x.Port.Description, x.Port.Abbreviation, x.MaxPax, x.Port.StopOrder }).OrderBy(x => x.Key.StopOrder).Select(x => new PortCalendarVM { Id = x.Key.PortId, Description = x.Key.Description, MaxPax = x.Key.MaxPax, AccumulatedMaxPax = NOW WHAT ??? }) }) }).ToList(); }
解决方案
LINQ的Select无法直接跨元素维护状态,因此需要在每个Destination分组内,先固定端口顺序并转为列表,再通过局部变量维护累积值。补全后的代码如下:
public IEnumerable<AvailabilityCalendarGroupVM> GetForCalendar(string fromDate, string toDate) { return context.Schedules .Where(x => x.Date >= Convert.ToDateTime(fromDate) && x.Date <= Convert.ToDateTime(toDate)) .GroupBy(x => x.Date) .Select(dateGroup => new AvailabilityCalendarGroupVM { Date = DateHelpers.DateTimeToISOString(dateGroup.Key.Date), Destinations = dateGroup .GroupBy(sched => new { sched.Destination.Id, sched.Destination.Description, sched.Destination.Abbreviation }) .Select(destGroup => { // 将当前Dest下的端口分组排序后转为列表,确保顺序固定 var portGroups = destGroup .GroupBy(sched => new { sched.PortId, sched.Port.Description, sched.MaxPax, sched.Port.StopOrder }) .OrderBy(pg => pg.Key.StopOrder) .ToList(); // 初始化累积值,每个Dest分组会自动重置为0 int accumulated = 0; var ports = portGroups.Select(pg => { accumulated += pg.Key.MaxPax; return new PortCalendarVM { Id = pg.Key.PortId, Description = pg.Key.Description, MaxPax = pg.Key.MaxPax, AccumulatedMaxPax = accumulated }; }).ToList(); return new DestinationCalendarVM { Id = destGroup.Key.Id, Description = destGroup.Key.Description, Abbreviation = destGroup.Key.Abbreviation, Ports = ports }; }) }).ToList(); }
逻辑说明
- 针对每个
Destination分组,先将排序后的端口分组转为列表,保证迭代顺序固定且可重复遍历 - 声明局部变量
accumulated,每个Destination分组初始化时该变量自动重置为0,实现分组间的累积值隔离 - 遍历端口分组时,每次将当前
maxPax累加到accumulated上,直接赋值给AccumulatedMaxPax
内容的提问来源于stack exchange,提问作者John Sourvinos
相关产品推荐
相关产品推荐

