如何使用Linq将邮政编码范围数组简化为最小范围集合
用LINQ合并重叠/连续的邮政编码范围
这是个很实用的需求!我们可以通过统一格式转换→排序→累积合并→格式还原这几个步骤,用LINQ优雅地实现这个功能。以下是具体的实现方案:
1. 定义辅助结构和工具方法
首先,我们需要一个统一的结构来表示邮政编码范围(不管是单个编码还是区间),同时需要一个工具方法来计算某个邮政编码的下一个连续编码:
// 用record来存储范围的起始和结束编码,简洁高效 public record PostalRange(string Start, string End); // 计算下一个连续的邮政编码(保持数字位数,比如 AA000 → AA001,EE815 → EE816) private static string IncrementPostalCode(string code) { // 分离字母部分和数字部分 var letterPart = new string(code.TakeWhile(char.IsLetter).ToArray()); var numberPart = code.Substring(letterPart.Length); if (int.TryParse(numberPart, out int number)) { // 递增数字并补零,保持原位数 return letterPart + (++number).ToString().PadLeft(numberPart.Length, '0'); } // 异常情况返回原编码(理论上不会出现合法邮政编码解析失败的情况) return code; }
2. 完整LINQ实现流程
接下来我们把整个流程串起来,从原始数组到合并后的结果:
// 原始邮政编码数组 var originalPostalCodes = new[] { "AA000-DD130", "DD131-DD150", "DD151-EE180", "EE300-EE600", "EE450-EE700", "EE800", "EE810", "EE811", "EE812", "EE813", "EE814", "EE815" }; // Step 1: 把所有编码转换为统一的PostalRange格式 var ranges = originalPostalCodes .Select(code => { var parts = code.Split('-'); return parts.Length == 2 ? new PostalRange(parts[0], parts[1]) : new PostalRange(code, code); // 单个编码的起始和结束都是自己 }) .OrderBy(r => r.Start) // Step 2: 按起始编码排序,确保合并顺序正确 .ToList(); // Step 3: 使用Aggregate累积合并重叠/连续的范围 var mergedRanges = ranges.Aggregate(new List<PostalRange>(), (accumulated, current) => { if (!accumulated.Any()) { // 第一个范围直接加入 accumulated.Add(current); return accumulated; } var lastRange = accumulated.Last(); var nextLastEnd = IncrementPostalCode(lastRange.End); // 判断是否可以合并:当前范围起始 ≤ 上一个范围结束,或者当前起始是上一个结束的下一个编码 if (string.Compare(current.Start, lastRange.End, StringComparison.Ordinal) <= 0 || string.Equals(current.Start, nextLastEnd, StringComparison.Ordinal)) { // 合并范围:取两个范围中更大的结束值 var newEnd = string.Compare(last(lastRange.End, current.End, StringComparison.Ordinal) >= 0 ? lastRange.End : current.End; accumulated.RemoveAt(accumulated.Count - 1); accumulated.Add(new PostalRange(lastRange.Start, newEnd)); } else { // 无法合并,直接加入新范围 accumulated.Add(current); } return accumulated; }); // Step 4: 把合并后的范围转换回目标字符串格式 var finalPostalCodes = mergedRanges .Select(r => r.Start == r.End ? r.Start : $"{r.Start}-{r.End}") .ToArray();
3. 结果验证
运行这段代码后,finalPostalCodes的结果就是你想要的:
["AA000-EE180", "EE300-EE700", "EE800", "EE810-EE815"]
关键逻辑说明
- 统一格式:不管输入是单个编码还是区间,都转成
PostalRange,避免分支判断混乱。 - 排序:必须按起始编码排序,这样我们才能按顺序检查每个范围是否能和前一个合并。
- 合并判断:用
string.Compare确保字母数字编码的正确排序,同时通过IncrementPostalCode判断是否是连续编码。 - Aggregate的使用:LINQ的
Aggregate非常适合这种累积合并的场景,不需要额外的循环变量,代码更简洁。
内容的提问来源于stack exchange,提问作者Melipao
相关产品推荐
相关产品推荐

