как отсортировать строки в javascript численно - PullRequest
8 голосов
/ 13 ноября 2011

Я хотел бы отсортировать массив строк (в javascript) так, чтобы группы цифр в строках сравнивались как целые числа, а не строки. Я не беспокоюсь о числах со знаком или с плавающей запятой.

например, результат должен быть ["a1b3","a9b2","a10b2","a10b11"], а не ["a1b3","a10b11","a10b2","a9b2"]

Самый простой способ сделать это, кажется, разделить каждую строку на границы вокруг групп цифр. Есть ли шаблон, который я могу передать String.split для разделения по границам символов без удаления каких-либо символов?

"abc11def22ghi".split(/?/) = ["abc","11","def","22","ghi"];

Или есть другой способ сравнения строк, который не включает их разбиение, возможно, добавляя все группы цифр начальными нулями, чтобы они были одинаковой длины?

"aa1bb" => "aa00000001bb", "aa10bb" => "aa00000010bb"

Я работаю с произвольными строками, а не со строками, которые имеют определенное расположение групп цифр.

Edit:

Мне нравится /(\d+)/ один вкладыш от Gaby для разделения массива. Насколько это обратно совместимо?

Решения, которые разбирают строки один раз так, чтобы их можно было использовать для восстановления оригиналов, намного эффективнее, чем эта функция сравнения. Ни один из ответов не обрабатывает некоторые строки, начинающиеся с цифр, а другие нет, но это было бы достаточно легко исправить, и это не было явно в исходном вопросе.

["a100","a20","a3","a3b","a3b100","a3b20","a3b3","!!","~~","9","10","9.5"].sort( function ( inA , inB ) {
    var                     result = 0;

    var                     a , b , pattern = /(\d+)/;
    var                     as = inA.split( pattern );
    var                     bs = inB.split( pattern );
    var                     index , count = as.length;

    if ( ( '' === as[0] ) === ( '' === bs[0] ) ) {
        if ( count > bs.length ) count = bs.length;

        for ( index = 0 ; index < count && 0 === result ; ++index ) {
            a = as[index]; b = bs[index];

            if ( index & 1 ) {
                result = a - b;
            } else {
                result = !( a < b ) ? ( a > b ) ? 1 : 0 : -1;
            }
        }

        if ( 0 === result ) result = as.length - bs.length;
    } else {
        result = !( inA < inB ) ? ( inA > inB ) ? 1 : 0 : -1;
    }

    return result;
} ).toString();

результат: "!!,9,9.5,10,a3,a3b,a3b3,a3b20,a3b100,a20,a100,~~"

Ответы [ 6 ]

16 голосов
/ 13 ноября 2011

Я думаю, что это то, что вы хотите

function sortArray(arr) {
    var tempArr = [], n;
    for (var i in arr) {
        tempArr[i] = arr[i].match(/([^0-9]+)|([0-9]+)/g);
        for (var j in tempArr[i]) {
            if( ! isNaN(n = parseInt(tempArr[i][j])) ){
                tempArr[i][j] = n;
            }
        }
    }
    tempArr.sort(function (x, y) {
        for (var i in x) {
            if (y.length < i || x[i] < y[i]) {
                return -1; // x is longer
            }
            if (x[i] > y[i]) {
                return 1;
            }
        }
        return 0;
    });
    for (var i in tempArr) {
        arr[i] = tempArr[i].join('');
    }
    return arr;
}
alert(
    sortArray(["a1b3", "a10b11", "a10b2", "a9b2"]).join(",")
);
6 голосов
/ 13 ноября 2011

Используйте эту функцию сравнения для сортировки ..

function compareLists(a,b){
    var alist = a.split(/(\d+)/), // split text on change from anything to digit and digit to anything
        blist = b.split(/(\d+)/); // split text on change from anything to digit and digit to anything

    alist.slice(-1) == '' ? alist.pop() : null; // remove the last element if empty
    blist.slice(-1) == '' ? blist.pop() : null; // remove the last element if empty

    for (var i = 0, len = alist.length; i < len;i++){
        if (alist[i] != blist[i]){ // find the first non-equal part
           if (alist[i].match(/\d/)) // if numeric
           {
              return +alist[i] - +blist[i]; // compare as number
           } else {
              return alist[i].localeCompare(blist[i]); // compare as string
           }
        }
    }

    return true;
}

Синтаксис

var data = ["a1b3","a10b11","b10b2","a9b2","a1b20","a1c4"];
data.sort( compareLists );
alert(data);

демо на http://jsfiddle.net/h9Rqr/7/

5 голосов
/ 13 ноября 2011

Предполагая, что вы хотите просто выполнить числовую сортировку по цифрам в каждой записи массива (игнорируя не-цифры), вы можете использовать это:

function sortByDigits(array) {
    var re = /\D/g;

    array.sort(function(a, b) {
        return(parseInt(a.replace(re, ""), 10) - parseInt(b.replace(re, ""), 10));
    });
    return(array);
}

Он использует пользовательскую функцию сортировки, которая удаляет цифры и конвертирует в число каждый раз, когда его просят сделать сравнение. Вы можете увидеть его здесь: http://jsfiddle.net/jfriend00/t87m2/.

Если это не то, что вы хотите, то, пожалуйста, уточните, поскольку ваш вопрос не очень ясен по поводу того, что сортировка должна работать.

1 голос
/ 13 ноября 2011

Вот более полное решение , которое сортирует по буквам и цифрам в строках

function sort(list) {
    var i, l, mi, ml, x;
    // copy the original array
    list = list.slice(0);

    // split the strings, converting numeric (integer) parts to integers
    // and leaving letters as strings
    for( i = 0, l = list.length; i < l; i++ ) {
        list[i] = list[i].match(/(\d+|[a-z]+)/g);
        for( mi = 0, ml = list[i].length; mi < ml ; mi++ ) {
            x = parseInt(list[i][mi], 10);
            list[i][mi] = !!x || x === 0 ? x : list[i][mi];
        }
    }

    // sort deeply, without comparing integers as strings
    list = list.sort(function(a, b) {
        var i = 0, l = a.length, res = 0;
        while( res === 0 && i < l) {
            if( a[i] !== b[i] ) {
                res = a[i] < b[i] ? -1 : 1;
                break;
            }

            // If you want to ignore the letters, and only sort by numbers
            // use this instead:
            // 
            // if( typeof a[i] === "number" && a[i] !== b[i] ) {
            //     res = a[i] < b[i] ? -1 : 1;
            //     break;
            // }

            i++;
        }
        return res;
    });

    // glue it together again
    for( i = 0, l = list.length; i < l; i++ ) {
        list[i] = list[i].join("");
    }
    return list;
}
0 голосов
/ 08 февраля 2018

Мне нужен был способ взять смешанную строку и создать строку, которую можно было бы отсортировать в другом месте, чтобы числа сортировались по номерам, а буквы - по алфавиту.Основываясь на ответах выше, я создал следующее, которое выводит все числа таким образом, чтобы я мог понять, где бы они ни появлялись в строке.

function padAllNumbers(strIn) {
    // Used to create mixed strings that sort numerically as well as non-numerically
    var patternDigits = /(\d+)/g; // This recognises digit/non-digit boundaries
    var astrIn = strIn.split( patternDigits ); // we create an array of alternating digit/non-digit groups

    var result = "";

    for (var i=0;i<astrIn.length;  i++) {
        if (astrIn[i] != "") { // first and last elements can be "" and we don't want these padded out
            if (isNaN(astrIn[i])) {
                result += astrIn[i];
            } else {
                result += padOneNumberString("000000000",astrIn[i]);
            }
        }
    }
    return result;
}

function padOneNumberString(pad,strNum,left) {
    // Pad out a string at left (or right)
    if (typeof strNum === "undefined") return pad;
    if (typeof left === "undefined") left = true;
    var padLen =  pad.length - (""+ strNum).length;
    var padding = pad.substr(0,padLen);
    return left?  padding + strNum : strNum + padding;
}
0 голосов
/ 13 ноября 2011

Сортировка происходит слева направо, если вы не создадите пользовательский алгоритм.Буквы или цифры сравниваются сначала с цифрами, а затем с буквами.

Однако то, что вы хотите выполнить в соответствии с вашим собственным примером (a1, a9, a10), никогда не будет.Это потребовало бы, чтобы вы знали данные заранее и разбивали строку всеми возможными способами перед применением сортировки.

Одна последняя альтернатива будет:

a) разбить каждую строку слева направоправо всякий раз, когда происходит смена буквы на цифру и наоборот;и б) затем начать сортировку по этим группам справа налево.Это будет очень требовательный алгоритм.Может быть сделано!

Наконец, если вы являетесь ГЕНЕРАТОРОМ исходного «текста», вам следует рассмотреть НОРМАЛИЗАЦИЮ выходных данных, где a1 a9 a10 может быть вычислено как a01 a09 a10.Таким образом, вы можете получить полную версию окончательного варианта алгоритма.

Удачи!

...