0

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]')

21
  • Can you post a failing example of your use case. As long as all the elements in listitems are all strings or numbers it should not be a problem. Commented Oct 4, 2017 at 0:48
  • @Xufox "80" > "9" and 80 > 9 will give you the same results. As long as a and b are of the same primitive type, should not be a problem. The issue arises only if one is a number and another is a string. Commented Oct 4, 2017 at 0:50
  • I updated my post. It has to work on mixed characters, not only int. Commented Oct 4, 2017 at 0:50
  • 2
    @Sushanth-- "80" > "9" and 80 > 9 will give you the same results.” — this is false. Commented Oct 4, 2017 at 0:51
  • @Xufox My bad. You are right. Commented Oct 4, 2017 at 0:52

2 Answers 2

2

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>

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks! I get this: SyntaxError: Unexpected token '...'. Expected a property name.
oh dear @SeaBass - are you using a microsoft browser? - let me "transpile" that for you
hehe latest Safari. Maybe there's some other stuff in my code that screw it up.
@SeaBass - try now, if that doesn't work, I'll post pre 2015 javascript
@SeaBass - see if that vanilla pre 2015 version of code works - looks damn ugly now
|
0

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);

8 Comments

Thanks, I see it working in your code with an array, but I don't know how to make it work with my code in the original post.
can you provide me with more information which data to you want to compare? You can add html code as an example
My whole function is in my original post. I have a table with cells and want them to be ordered the way described.
Or lets put it this way. Ignore my code. How can I apply this method to sort a table with rows based on the text vale in the first cell of each row?
Updated! Function ' compare' returns value 1 / -1 for sorting just use argument a, b for compare function in array mode
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.