Reputation: 1764
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
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
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