混合字母/数字数组排序

93

我有一个混合数组,需要按字母表顺序和数字顺序排序

[A1, A10, A11, A12, A2, A3, A4, B10, B2, F1, F12, F3]

如何排序才能得到:

[A1, A2, A3, A4, A10, A11, A12, B2, B10, F1, F3, F12]

我已经尝试过

arr.sort(function(a,b) {return a - b});

但那只是按字母顺序排序。这个问题可以使用纯JavaScript或jQuery来解决吗?


数值总是在字符串的末尾吗? - Orbling
2
可能是如何在JavaScript中对字符串进行排序的重复问题。 - feeela
18个回答

2

以上解决方案的唯一问题是,当数字数据相同但字母不同时,逻辑会失败,例如28AB、28PQR、28HBC。 这是修改后的代码。

var reA = /[^a-zA-Z]/g;
    var reN = /[^0-9]/g;
    var AInt = parseInt(a, 10);
    var BInt = parseInt(b, 10);
    if(isNaN(AInt) && isNaN(BInt)){
        var aA = a.replace(reA, "");
        var bA = b.replace(reA, "");
        if(aA === bA) {
            var aN = parseInt(a.replace(reN, ""), 10);
            var bN = parseInt(b.replace(reN, ""), 10);
            alert("in if "+aN+" : "+bN);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
        } else {
            return aA > bA ? 1 : -1;
        }
    }else if(isNaN(AInt)){//A is not an Int
        return 1;//to make alphanumeric sort first return 1 here
    }else if(isNaN(BInt)){//B is not an Int
        return -1;//to make alphanumeric sort first return -1 here
    }else if(AInt == BInt) {
        var aA = a.replace(reA, "");
        var bA = b.replace(reA, "");
        return aA > bA ? 1 : -1;
    }
    else {
        return AInt > BInt ? 1 : -1;
    }

考虑到各种混合值的最佳答案 - 非常感谢! :) - meistermuh
把alert()从示例中移除,它就能正常工作了 :-) - Drew

1
这是一个ES6 TypeScript升级版本的答案。
export function SortAlphaNum(a: string, b: string) {
    const reA = /[^a-zA-Z]/g;
    const reN = /[^0-9]/g;
    const aA = a.replace(reA, "");
    const bA = b.replace(reA, "");
    if (aA === bA) {
      const aN = parseInt(a.replace(reN, ""), 10);
      const bN = parseInt(b.replace(reN, ""), 10);
      return aN === bN ? 0 : aN > bN ? 1 : -1;
    } else {
      return aA > bA ? 1 : -1;
    }
}

1

如果有人正在寻找使用localeCompare的更清晰的方法,那么请看这里。

arr.sort((a, b) => a.localeCompare(b, undefined,{ numeric: true }))

0
alphaNumericCompare(a, b) {

    let ax = [], bx = [];

    a.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { ax.push([$1 || Infinity, $2 || '']) });
    b.replace(/(\d+)|(\D+)/g, function (_, $1, $2) { bx.push([$1 || Infinity, $2 || '']) });

    while (ax.length && bx.length) {
       let an = ax.shift();
       let bn = bx.shift();
       let nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]);
       if (nn) {
         return nn;
       }
     }
     return ax.length - bx.length;
}

0

我已经用以下脚本解决了上述排序问题

arrVals.sort(function(a, b){
    //return b.text - a.text;
    var AInt = parseInt(a.text, 10);
    var BInt = parseInt(b.text, 10);

    if ($.isNumeric(a.text) == false && $.isNumeric(b.text) == false) {
        var aA = a.text
        var bA = b.text;
        return aA > bA ? 1 : -1;
    } else if ($.isNumeric(a.text) == false) {  // A is not an Int
        return 1;    // to make alphanumeric sort first return -1 here
    } else if ($.isNumeric(b.text) == false) {  // B is not an Int
        return -1;   // to make alphanumeric sort first return 1 here
    } else {
        return AInt < BInt ? 1 : -1;
    }
});

这对于一个混合良好的数组来说很好用。:)

谢谢。


0
这是一个基于 @SunnyPenguin 和 @Code Maniac 的答案的 TypeScript 库函数版本。变量名称已更新并添加了注释以提高清晰度。
// Sorts strings with numbers by keeping the numbers in ascending order
export const sortAlphaNum: Function = (a: string, b: string, locale: string): number => {
  const letters: RegExp = /[^a-zA-Z]/g;
  const lettersOfA: string = a.replace(letters, '');
  const lettersOfB: string = b.replace(letters, '');

  if (lettersOfA === lettersOfB) {
    const numbers: RegExp = /[^0-9]/g;
    const numbersOfA: number = parseInt(a.replace(numbers, ''), 10);
    const numbersOfB: number = parseInt(b.replace(numbers, ''), 10);

    if (isNaN(numbersOfA) || isNaN(numbersOfB)) {
      // One is not a number - comparing letters only
      return new Intl.Collator(locale, { sensitivity: 'accent' }).compare(a, b);
    }
    // Both have numbers - compare the numerical parts
    return numbersOfA === numbersOfB ? 0 : numbersOfA > numbersOfB ? 1 : -1;
  } else {
    // Letter parts are different - comparing letters only
    return new Intl.Collator(locale, { sensitivity: 'accent' }).compare(lettersOfA, lettersOfB);
  }
};

0

这对我很有用,而且更加紧凑。

const reg = /[0-9]+/g;

array.sort((a, b) => {
     let v0 = a.replace(reg, v => v.padStart(10, '0'));
     let v1 = b.replace(reg, v => v.padStart(10, '0'));
     return v0.localeCompare(v1);
});

-3
function sortAlphaNum(a, b) {
    var smlla = a.toLowerCase();
    var smllb = b.toLowerCase();
    var result = smlla > smllb ? 1 : -1;
    return result;
}

1
这是错误的。尝试将A10A2进行比较。这将使A10A2之前排序,但实际上A2应该在A10之前排序。 - Uyghur Lives Matter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接