You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:29:53