寻求更优雅高效的非指定整数区间小时列表实现方案
优化思路与实现方案
嘿,这个需求很明确!咱们来看看怎么把这段代码优化得更简洁高效~
首先,原方法的问题在于:每次遍历邮件时都调用RemoveAll,这会多次遍历小时列表,当邮件数量较多时,时间复杂度会达到O(m*n)(m是邮件数,n是小时数24),虽然24的基数不大,但逻辑上可以做得更优雅。
更好的思路是:先把所有需要排除的时间区间收集起来,合并重叠/相邻的区间,最后从1-24里筛选出不在任何合并区间内的小时。这样只需要遍历小时列表一次,效率和可读性都会提升。
具体实现代码
List<int> GetTimeList(List<Mail> Mails, int TransferSpeed) { // 1. 收集所有需要排除的有效时间区间(确保结束小时不超过24) var exclusionIntervals = Mails.Select(mail => { int startHour = mail.DateAndTime.Hour; int endHour = Math.Min(GetRoundedTransferTime(TransferSpeed, mail.Size), 24); return (Start: startHour, End: endHour); }) .Where(interval => interval.Start <= interval.End) // 过滤无效区间(比如结束时间早于开始时间的情况) .ToList(); // 如果没有需要排除的区间,直接返回完整小时列表 if (!exclusionIntervals.Any()) { return Enumerable.Range(1, 24).ToList(); } // 2. 合并重叠或相邻的区间,减少后续判断次数 var sortedIntervals = exclusionIntervals.OrderBy(interval => interval.Start).ToList(); var mergedIntervals = new List<(int Start, int End)> { sortedIntervals[0] }; foreach (var currentInterval in sortedIntervals.Skip(1)) { var lastMerged = mergedIntervals.Last(); // 如果当前区间和最后一个合并区间重叠/相邻,就合并它们 if (currentInterval.Start <= lastMerged.End + 1) { mergedIntervals.RemoveAt(mergedIntervals.Count - 1); mergedIntervals.Add((lastMerged.Start, Math.Max(lastMerged.End, currentInterval.End))); } else { mergedIntervals.Add(currentInterval); } } // 3. 筛选出不在任何合并区间内的小时 return Enumerable.Range(1, 24) .Where(hour => mergedIntervals.All(interval => hour < interval.Start || hour > interval.End)) .ToList(); }
优化点说明
- 效率提升:时间复杂度降到了O(m log m)(排序区间) + O(n + m)(合并区间+筛选小时),当邮件数量较多时,比原方法的多次遍历更高效。
- 代码简洁性:用
Enumerable.Range(1,24)替代手动初始化小时列表,减少硬编码;用LINQ处理区间收集,逻辑更清晰。 - 鲁棒性增强:加入了无效区间的过滤(比如计算出的结束时间早于开始时间的情况),避免错误的排除逻辑。
- 可读性更好:把逻辑拆分成三个明确的步骤,后续维护起来更轻松。
内容的提问来源于stack exchange,提问作者Tadas
相关产品推荐
相关产品推荐

