Javascript : natural sort of alphanumerical strings
This is now possible in modern browsers using localeCompare. By passing the numeric: true
option, it will smartly recognize numbers. You can do case-insensitive using sensitivity: 'base'
. Tested in Chrome, Firefox, and IE11.
Here's an example. It returns 1
, meaning 10 goes after 2:
'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})
For performance when sorting large numbers of strings, the article says:
When comparing large numbers of strings, such as in sorting large arrays, it is better to create an Intl.Collator object and use the function provided by its compare property. Docs link
var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));
Sort an array which contains number and strings
It seems you have done most of the work in your second attempt.
All I have done here is used Array.concat
to join the sorted results of number
and char
together.
var arr = [9, 5, '2', 'ab', '3', -1] // to be sortedvar number = [];var char = [];arr.forEach(a => { if (typeof a == 'number') number.push(a); else char.push(a);})
var sorted = number.sort().concat(char.sort());console.log(sorted)
Sort on a string that may contain a number
The Alphanum Algorithm
From the website
"People sort strings with numbers differently than software. Most sorting algorithms compare ASCII values, which produces an ordering that is inconsistent with human logic. Here's how to fix it."
Edit: Here's a link to the Java Comparator Implementation from that site.
NSFetchedResultsController - sort as a number but string field
var sortDescriptor = NSSortDescriptor(key: "title", ascending: true,
selector: #selector(NSString.localizedStandardCompare))
fetchRequest.sortDescriptors = [sortDescriptor]
Sort array of objects by string property value
It's easy enough to write your own comparison function:
function compare( a, b ) {
if ( a.last_nom < b.last_nom ){
return -1;
}
if ( a.last_nom > b.last_nom ){
return 1;
}
return 0;
}
objs.sort( compare );
Or inline (c/o Marco Demaio):
objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0))
Or simplified for numeric (c/o Andre Figueiredo):
objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort
Javascript sort string or number
The problem might be that you're calling the jQuery constructor a bunch of times and doing heavy operations on it (e.g. using .find()
with complex selectors). Therefore, your function is just slow and that's probably the issue.
The good news is that JavaScript has a native implementation of QuickSort (a very fast sorting function) that will probably take care of your needs. When combined with a reduction in expensive calls, your code should end up being enormously more efficient. I'd change your code to look like this:
var sortByField = function(field, mode) {
var numExp = /^-?\d*\.?\d+$/;
var $rows = $(".data tr:not(.hdr)"), $table = $(".data");
$rows.each(function () {
this.fieldVal = $(this).find("td:eq("+field+")").text();
if(numExp.test(this.fieldVal)) { //if field is numeric, convert it to a number
this.fieldVal = +this.fieldVal;
}
}).sort(function (a, b) {
if (mode === 1) {
return (a.fieldVal > b.fieldVal) ? -1 : 1;
}
return (a.fieldVal < b.fieldVal) ? -1 : 1;
}).detach().each(function () {
$(this).appendTo($table);
});
};
This won't work well with multiple tables on one page (because it assumes everything is on the same table). So if you want to do that, you should pass in the table or table selector as a parameter. But that's an easy fix to make. You can see my solution in action here:
http://jsfiddle.net/r8wtK/ (updated)
It should be far more efficient than your code and should reduce "freezing" by quite a bit (ore even entirely).
UPDATE:
The OP noted that some fields may contain strings. Doing a string comparison on numbers is bad because it returns a lexicographical ordering (e.g. "10" < "2"
). So I added a test to see if the data appear to be numeric before doing the sort.
Sorting numbers cast as strings in react
parseInt()
won't work on strings with commas in them, you'll have to remove them manually when you sort:
customSort: (a, b) => parseInt(a.salary.replace(/,/g, '')) - parseInt(b.salary.replace(/,/g, ''))
Related Topics
Conditions in Left Join (Outer Join) VS Inner Join
Sql: Syntax Error with Intersect
Oracle 12C - Select String After Last Occurrence of a Character
Select * from Table or Select Id,Field1, Field2, Field3 from Table - Best Practice
Summarize the List into a Comma-Separated String
SQL Query That Distinguishes Between ß and Ss
How to Use a Pg Sequence on a Per Record Label
How Does SQL Server Wildcard Character Range, Eg [A-D], Work with Case-Sensitive Collation
Oracle - Literal Does Not Match Format String Error
SQL Primary Key - Is It Necessary
Simple Update Statement So That All Rows Are Assigned a Different Value
SQL Identity with Leading Padded Zeros
What Happens with Duplicates When Inserting Multiple Rows
Calculating SQL Server Row_Number() Over() for a Derived Table