我有一个用compareFunction排序的Java字符串数组。在大多数情况下,它可以正确排序:

JS

array = ["E10N1", "E10N3", "E10N10", "E10N2", "E10N4", "E10N9", "E10N5", "E10N8", "E10N6", "E10N7"];

function sortStrings(a, b){
    if(a < b){
        return -1;
    }
    if(a > b){
        return 1;
    }
    return 0;
}

array.sort(sortStrings);
for(var i = 0; i < array.length; i++){
    $(".table_body").append("<div class='table_row'><p>" +array[i] +"</p></div>");
}


我遇到的问题是排序功能是将"E10N10"项目放在"E10N1""E10N2"项目之间。所以看起来像这样:

javascript - 数组无法在JavaScript中正确排序-LMLPHP

我知道排序字符串是按字母顺序进行的,但是"E10N10"字符串是否仍要晚于"E10N9"进行处理?如何解决该特定字符串在排序后排在数组的最后的问题?

最佳答案

按照字母顺序,它只是顺序地查看字符,因此即使“ E10N1”之后还有另一个字符,“ E10N1”也将位于“ E10N9”之前。就像“ abcd”在“ abd”之前一样。

如果您确实想要所需的排序类型,则需要采用一种更为复杂的自定义排序算法,该算法实际上是解析标签的数字部分,以便对其进行实际的数字比较(而不是字母排序)。

这是一个基于尾随数字进行排序的排序方案:



var array = ["E10N1", "E10N3", "E10N10", "E10N2", "E10N4", "E10N9", "E10N5", "E10N8", "E10N6", "E10N7"];

var regex = /\d+$/;
function getLastNum(str) {
    var m = str.match(regex);
    if (m) {
        return parseInt(m[0], 10);
    } else {
        return -1;
    }
}

array.sort(function(a, b) {
    return getLastNum(a) - getLastNum(b);
});
document.write(JSON.stringify(array));





您显然可以根据需要使它复杂或丰富。例如,如果您要标识数字中的所有数字序列并将其转换为实际数字,则也可以这样做。您没有指定需要如何参与,因此我展示了使您的特定序列正常工作所需的最小工作(仅按尾数进行排序)。

要讨论几种用于处理混合的字母数字排序的通用算法,其中数字可以出现在字符串中的任何位置,并且可以出现在多个位置,请参见本文:Sorting for Humans: Natural Sort Order。可以在here中找到Javascript中的一种特定实现。

通用算法背后的总体思路如下:

Get the next character of each string
If not both digits, then compare the characters directly and return the result
If both digits, then collect sequence of digits in both strings
    Longest sequence of consecutive digits is higher
    While accumulating sequential digits, keep track of which sequence
       has the first non-equal digit that is higher than the other
    If sequences were the same length, then the previous collected value
       of which sequence had the first different higher number determines
       which sequence comes first
If sequence of digits or single character were equal, go to next character
    and start the above process over


这种通用算法的一个优点是,它实际上不会将数字的数字序列转换为数字,因此它将在任意长度的数字序列上工作,而不会限制Javascript中可以包含多少个数字。

根据您所需的算法,您可能会或可能不想忽略空格的前两位数字,并且可能会也可能不想考虑数字前面的加号或减号。并且,您可能希望使用语言感知的比较,而不是严格的ASCII代码比较。对于任何特定用途,有很多因素要考虑。



这是我从头开始编写的通用算法:



var array = ["E10N1", "E10N3", "E10N10", "E10N2", "E10N4", "E10N9", "E10N5",
   "E10N8", "E10N6", "E10N7", "C10N1", "D10N3", "E11N10", "E09N2", "E999N4",
   "E10000N9", "g10N6", "z10N6", "q10N6", "R10N6", "E001N1", "E00N1",
   "E0000N1", "zN1", "zN000", "zN00", "000", "00", "0001", "0002", "A00",
   "A", "0A"];
// return negative value if a < b
// return 0 if a === b
// return positive value if a > b
//
// Rules:
// - Sort characters before numbers
// - Ignore leading zeroes on digits
// - Ignore plus/minus signs in front of digits
// - For sequences of zeroes the shorter sequence is first
//
function alphaNumCompare(a, b) {
    var aIndex = 0,
        bIndex = 0,
        aChar, bChar, result;

    function isDigit(ch) {
        return ch >= "0" && ch <= "9";
    }

    function compareNums() {
        // aChar, bChar contain first digit
        // get rest of consecutive digits and compare
        // returns negative, 0 or positive
        // as side affect, advances aIndex and bIndex to next non-numeric
        var aZeroLen = 0,
            bZeroLen = 0,
            aNumStr = "",
            bNumStr = "";
        // collect consecutive digits from a and b
        // ignore any leading zeroes
        if (aChar === "0") {
            ++aZeroLen;
        } else {
            aNumStr = aChar;
        }
        if (bChar === "0") {
            ++bZeroLen;
        } else {
            bNumStr = bChar;
        }
        while (aIndex < a.length) {
            aChar = a.charAt(aIndex);
            if (!isDigit(aChar)) {
                break;
            }
            ++aIndex;
            // don't add leading zeroes and keep a count of leading zeroes
            if (aChar === "0" && aNumStr === "") {
                ++aZeroLen;
            } else {
                aNumStr += aChar;
            }
        }
        while (bIndex < b.length) {
            bChar = b.charAt(bIndex);
            if (!isDigit(bChar)) {
                break;
            }
            ++bIndex;
            // don't add leading zeroes and keep a count of leading zeroes
            if (bChar === "0" && bNumStr === "") {
                ++bZeroLen;
            } else {
                bNumStr += bChar;
            }
        }
        // we now have a series of consecutive digits in aNumStr and bNumStr
        if (aNumStr.length === bNumStr.length) {
            // check for nothing but leading zeroes in both
            if (aNumStr.length === 0) {
                return aZeroLen - bZeroLen;
            }
            if (aNumStr === bNumStr) {
                return 0;
            } else {
                return aNumStr < bNumStr ? -1 : 1;
            }
        } else {
            // lengths are not equal, then shorter string comes first
            return aNumStr.length - bNumStr.length;
        }
    }
    // loop while both strings have characters left
    while (aIndex < a.length && bIndex < b.length) {
        aChar = a.charAt(aIndex++);
        bChar = b.charAt(bIndex++);
        if (isDigit(aChar) && isDigit(bChar)) {
            result = compareNums();
            if (result !== 0) {
                return result;
            }
        } else {
            // not both numeric, just compare the characters themselves
            result = aChar.localeCompare(bChar);
            if (result !== 0) {
                return result;
            }
        }
    }
    // shorter one is first
    return (a.length - aIndex) - (b.length - bIndex);
}

array.sort(alphaNumCompare);
document.write(JSON.stringify(array).replace(/,/g, ", "));





逻辑如下:


为Array sort()函数实现自定义排序函数。
获取字符串中的下一个字符
如果两者都是数字,则累积任何连续的数字序列。
从零序列中修剪前导零
如果两个序列都只是一个零序列,则较短的序列会更少
较短的数字序列小于较长的数字
如果两个数字序列的长度相同,则只需对它们进行直线比较即可得出结果
如果两个字符都不是数字,则将它们作为字符串进行比较
如果比较的字符串等于一个结束的点,则较短的那个较小

07-24 18:54
查看更多