版本号排序的方法

实现一个函数对版本号字符串数组进行正确排序,支持多段版本号比较

问题

在实际开发中,我们经常需要对软件版本号进行排序,比如 ['1.2.3', '1.0.0', '2.1.0']。版本号不能简单地按字符串排序,因为 '1.10.0' 应该大于 '1.9.0',但字符串排序会得到相反的结果。

需要实现一个函数,能够正确地对版本号数组进行升序或降序排序。

解答

/**
 * 比较两个版本号的大小
 * @param {string} version1 - 版本号1
 * @param {string} version2 - 版本号2
 * @returns {number} - 返回 -1(v1<v2), 0(v1=v2), 1(v1>v2)
 */
function compareVersion(version1, version2) {
  // 将版本号按 '.' 分割成数组
  const v1 = version1.split('.');
  const v2 = version2.split('.');
  
  // 取两个版本号的最大长度
  const maxLength = Math.max(v1.length, v2.length);
  
  // 逐段比较
  for (let i = 0; i < maxLength; i++) {
    // 将每段转换为数字,如果不存在则为 0
    const num1 = parseInt(v1[i] || 0, 10);
    const num2 = parseInt(v2[i] || 0, 10);
    
    if (num1 > num2) {
      return 1;
    } else if (num1 < num2) {
      return -1;
    }
    // 相等则继续比较下一段
  }
  
  // 所有段都相等
  return 0;
}

/**
 * 对版本号数组进行排序
 * @param {string[]} versions - 版本号数组
 * @param {string} order - 排序方式 'asc'(升序) 或 'desc'(降序)
 * @returns {string[]} - 排序后的版本号数组
 */
function sortVersions(versions, order = 'asc') {
  return versions.sort((a, b) => {
    const result = compareVersion(a, b);
    // 如果是降序,则反转比较结果
    return order === 'desc' ? -result : result;
  });
}

使用示例

// 示例1: 基本使用
const versions1 = ['1.2.3', '1.0.0', '2.1.0', '1.10.0', '1.9.0'];
console.log(sortVersions(versions1, 'asc'));
// 输出: ['1.0.0', '1.2.3', '1.9.0', '1.10.0', '2.1.0']

console.log(sortVersions(versions1, 'desc'));
// 输出: ['2.1.0', '1.10.0', '1.9.0', '1.2.3', '1.0.0']

// 示例2: 不同长度的版本号
const versions2 = ['1.0', '1.0.0', '1.0.1', '1'];
console.log(sortVersions(versions2, 'asc'));
// 输出: ['1', '1.0', '1.0.0', '1.0.1']

// 示例3: 复杂版本号
const versions3 = ['2.0.0', '1.9.9', '1.10.0', '1.9.10', '2.0.0-beta'];
console.log(sortVersions(versions3, 'asc'));
// 输出: ['1.9.9', '1.9.10', '1.10.0', '2.0.0', '2.0.0-beta']

// 示例4: 单独使用比较函数
console.log(compareVersion('1.10.0', '1.9.0')); // 输出: 1
console.log(compareVersion('1.0.0', '1.0.0')); // 输出: 0
console.log(compareVersion('1.0.0', '2.0.0')); // 输出: -1

关键点

  • 分段比较:将版本号按 . 分割成数组,逐段进行数值比较而非字符串比较
  • 数值转换:使用 parseInt() 将每段转换为数字,避免字符串比较的错误(如 ‘10’ < ‘9’)
  • 长度不一致处理:当版本号段数不同时,缺失的段视为 0(如 ‘1.0’ 等同于 ‘1.0.0’)
  • 比较函数返回值:返回 -1、0、1 三种值,符合 Array.sort() 的比较函数规范
  • 排序方向控制:通过反转比较结果实现升序和降序的切换
  • 边界情况:正确处理空段、单段版本号等特殊情况