Sort a table fast by its first column with Javascript or jQuery
I have a table which is dynamically populated from FullCalendar
.
The problem is that FullCalendar
does not care about its original order.
The table looks like this:
<table id="caltbl">
<thead>
<tr> <th> </th> <th> Date </th> <th> hours </th> ... </tr>
</thead>
<tbody>
<tr> &l开发者_开发问答t;td class="sortnr">1</td> <td></td> ... </tr>
<tr> <td class="sortnr">3</td> <td></td> ... </tr>
<tr> <td class="sortnr">2</td> <td></td> ... </tr>
<tr> <td class="sortnr">4</td> <td></td> ... </tr>
</tbody>
</table>
The first of each row contains the number on which the table should be sorted.
I had this code to sort it:
var rows = $('#caltbl > tbody').children('tr').detach();
for (var counter = 1; counter<=rows.length; counter++) {
$(rows).each(function(index) {
if ($(this).find(".sortnr").text()==counter){
$('#caltbl > tbody:last').append($(this));
}
});
}
This works fine in Firefox but causes me a major headache in Internet Explorer because there are more than 500 items and it hangs. I could add a setTimeout
but that would not fix the real problem. The sorting is slow. What is a faster way to sort this?
Instead of having to start from the <table>
html, as I said it gets populated dynamically so I have an Array
which contains the html. 1 item per <tr>
(unsorted)
Fiddle: http://jsfiddle.net/qNwDe/
I've written an efficient, cross-browser method to sort the rows in your table. Multiple JQuery selectors in double loops are causing serious performance issues (as you've noticed), hence I've get rid of JQuery.
An additional advantage of my function is that it doesn't mind missing index numbers. I'm currently referring to the first cell of each row, rather than getting the element by class name. If you want to refer by classname, I will alter my function:
function sortTable(){
var tbl = document.getElementById("caltbl").tBodies[0];
var store = [];
for(var i=0, len=tbl.rows.length; i<len; i++){
var row = tbl.rows[i];
var sortnr = parseFloat(row.cells[0].textContent || row.cells[0].innerText);
if(!isNaN(sortnr)) store.push([sortnr, row]);
}
store.sort(function(x,y){
return x[0] - y[0];
});
for(var i=0, len=store.length; i<len; i++){
tbl.appendChild(store[i][1]);
}
store = null;
}
Call sortTable()
whenever you want to sort the table.
Try an approach like this: http://jsfiddle.net/qh6JE/
var rows = $('#caltbl > tbody').children('tr').get(); // creates a JS array of DOM elements
rows.sort(function(a, b) { // use a custom sort function
var anum = parseInt($(a).find(".sortnr").text(), 10);
var bnum = parseInt($(b).find(".sortnr").text(), 10);
return anum-bnum;
});
for (var i = 0; i < rows.length; i++) { // .append() will move them for you
$('#caltbl > tbody').append(rows[i]);
}
I think there are way too many loops in your case. With 500 items, you would loop 500*500 = 250000 times . Not so many browsers would know how to do that.
I suggest using the native array.sort()
method of javascript to do the sorting based on a custom "comparison function".
Here is how it could be done (and most probably it can be optimized) : http://jsfiddle.net/tsimbalar/Dw6QE/.
The idea is to sort a list of rows comparing the sortNumber value ...
We can use jquery insead of javascript for the same thing answered by Rob W. It will not affect any performance issue like Multiple JQuery selectors in double loops.
var $tbody = $('table tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = $(a).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
var tdb = $(b).find('td:eq(' + ColumnIndex + ')').text(); // Use your wished column index
// if a < b return 1
return tda > tdb ? 1
// else if a > b return -1
: tda < tdb ? -1
// else they are equal - return 0
: 0;
}).appendTo($tbody);
Use < instead of >for descending.
FIDDLE
Check out this http://square.github.com/crossfilter/ the team at Square has used a clever bitmap index technique to allow filtering 5.3MB data in <30ms ... I am not sure if this helps, but it is a very interesting technique
精彩评论