SeaBass
SeaBass

Reputation: 1764

Javascript sort numerically instead of alphabetically

I have a function to sort rows alphabetically and it works pretty good, but if it contains numbers it will sort it a1, a10, a11, ..., a2, a20, ..., a3 instead of a1, a2, a3 etc.

function sort(element) {
 var sortableList = element;
 var listitems = $('tr', sortableList);

 listitems.sort(function (a, b) {

     return ($(a).find('td.myclass').text().toUpperCase() > $(b).find('td.myclass').text().toUpperCase()) ? 1 : -1;
 });
 sortableList.append(listitems);

}

Trying with this code form the example below. Not working yet:

function sort(element) {
 var sortableList = element;
 var listitems = $('tr', sortableList);
 var word = /[a-z]/i,
    digit = /\d+/;

listitems.sort(function (a, b) {
   return +$(a).find('td.myclass').text().match(digit)[0] > +$(b).find('td.myclass').text().match(digit)[0] ? 1 : -1;
}).sort(function (a, b) {
   return $(a).find('td.myclass').text().match(word)[0] > $(b).find('td.myclass').text().match(word)[0] ? 1 : -1;
});
 sortableList.append(listitems);

}

Error: null is not an object (evaluating '$(b).find('td.myclass').text().match(digit)[0]')

Upvotes: 0

Views: 147

Answers (2)

Jaromanda X
Jaromanda X

Reputation: 1

I think this should work as expected, regardless of complexity of text ...

function sort(sortableList) {
    $(sortableList).append([].slice.call($('tr', sortableList)).map(function (e) {
        return { element: e, values: ($(e).find('td').text().toUpperCase() || '').match(/([A-Z]+|\d+)/g) };
    }).sort(function (aa, bb) {
        var valuesA = aa.values ||[];
        var valuesB = bb.values ||[];
        var len = Math.min(valuesA.length, valuesB.length);
        for (var i = 0; i < len; i++) {
            var a = valuesA[i];
            var b = valuesB[i];
            if (a === b) {
                continue;
            }
            var aIsNum = !isNaN(parseInt(a));
            var bIsNum = !isNaN(parseInt(b));
            if (aIsNum && bIsNum) {
                return parseInt(a) - parseInt(b);
            }
            if (!(aIsNum && bIsNum)) {
                return a > b ? 1 : -1;
            }
            if (aIsNum) {
                return -1;
            }
            return 1;
        }
        return valuesA.length - valuesB.length;
    }).map(function (e) {
        return e.element;
    }));
    document.getElementById('msg').textContent = 'Sorted';
}
setTimeout(function () {
    return sort(document.querySelector('table'));
}, 2000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="msg">Wait for it ....</span>
<table>
    <tr>
        <td>a100</td>
    </tr>
    <tr>
        <td>a10</td>
    </tr>
    <tr>
        <td>b100</td>
    </tr>
    <tr>
        <td>a20</td>
    </tr>
    <tr>
        <td>a1</td>
    </tr>
    <tr>
        <td>a2</td>
    </tr>
    <tr>
        <td style="background:red"></td>
    </tr>
    <tr>
        <td>5</td>
    </tr>
    <tr>
        <td>a</td>
    </tr>
    <tr>
        <td>b1</td>
    </tr>
</table>

Upvotes: 2

zhuravlyov
zhuravlyov

Reputation: 493

Try this

"use strict";

let myArr = ['a1', 'c', 'c56','a', 'ac2', 'ab21', 1, '5a', 6, 'A16', 'b', 3, 'a3', 'abc'];
let result = [];

function compareNumeric(a, b) {
    return parseInt(a) - parseInt(b);
}

function compareStr(a, b) {
    return a.toUpperCase() > b.toUpperCase();
}

function compareStrNum(a, b) {
    if (a.match(/[a-z]+/i)[0].toUpperCase() === b.match(/[a-z]+/i)[0].toUpperCase()) {
        if (a.match(/\d+/) === null) {
            return 0;
        }

        return +a.match(/\d+/)[0] - +b.match(/\d+/)[0];
    }
}

function compare(arr) {
    let numeric = [];
    let str = [];

    for (let i = 0, max = arr.length; i < max; i++) {

        if (parseInt(arr[i])) {
            numeric.push(arr[i]);
        } else {
            str.push(arr[i]);
        }
    }

    numeric = numeric.sort(compareNumeric);
    str.sort(compareStr)
        .sort(compareStrNum);

    result = result.concat(numeric);
    result = result.concat(str);
}

compare(myArr);
console.log(result);

Upvotes: 0

Related Questions