0

I have a var which takes an array of values, these values are either alphanumeric or numbers but as alphanumerics, the question is what's the most efficient way to apply sorting based on the values? I want alphabetical sorting for the alphanumeric values and ascending order when it contains numbers.

By far i know that

var myArr=['c','a','b']
myArr.sort(); //gives output a,b,c

and if later on:

myArr=['10','1','2'];
myArr.sort();// gives 1,10,2 

but is there a fast way to decide which method of sorting to use based on the array's contents?

Thanks in advance!

sstauross
  • 2,602
  • 2
  • 30
  • 50
  • are you looking for that? http://stackoverflow.com/questions/1063007/arr-sort-does-not-sort-integers-correctly – ius Nov 03 '14 at 12:50
  • 1
    Yes. `typeof myArr[0]` will return either `'string'` or `'number'`. This coupled with a conditional gives you exactly what you need. – Sergiu Paraschiv Nov 03 '14 at 12:50
  • You have for example "ab" and "abc" which one you want to put first (i mean what is the criteria that you require for alphabetic characters) – ismnoiet Nov 03 '14 at 12:53

3 Answers3

1

But if the array elements are consistent (always numeric strings or always non-numeric strings), you can test one of them and then make the decision.

myArr.sort(/^\d+$/.test(myArr[0]) ? numericComparison : stringComparison);

...where stringComparison might be:

function stringComparisons(a, b) {
    return a.localeCompare(b);

}

...and numericComparison would be as shown in your question.

If they aren't consistent, then I don't see that you have an option other than pre-scanning the array to see what you're dealing with, and then sorting accordingly, since you can't cancel a sort operation in the middle, so you can't assume one but switch to the other mid-way.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • check the updated question.. the second case refers to array of numbers but in the form of strings. What can i do for this case? – sstauross Nov 03 '14 at 13:05
  • @sstauross: Check for digits: `if (/^\d+$/.test(myArr[0])) ...` I've updated the answer to show that. – T.J. Crowder Nov 03 '14 at 13:07
0

The only way to know if everything in a list is a number is to touch everything in the list. For instance, you can write a function to decide if everything is a number:

function hasOnlyNumbers(arr) {
    var l = arr.length;
    for (var i = 0; i < l; i++) {
        if (isNaN(arr[i]) {
            return false;
        }
    }
    return true;
}

Then, you can use the result of that to do your sorting. If they are all numbers, sort numerically, otherwise sort alphabetically can now be implemented with:

if (hasOnlyNumbers(myArr)) { 
    myArr.sort(sortNumber);
} else {
    myArr.sort();
}

Since any non-numeric item implies that it should be sorted alphabetically, this is about as good as you can do because the hasOnlyNumbers function returns as soon as it finds something that is not a number. Of course, you need to understand what isNaN does, because it may call things numbers that you aren't expecting (like 25E7 is exponential notation for a perfectly valid number, and isNaN returns false).

Zach
  • 156
  • 2
  • Sure, but can we start writing `!arr.some(isNaN)`? –  Nov 03 '14 at 13:08
  • This is not a part of the JavaScript standard, and is not cross-browser compatible. – Zach Nov 03 '14 at 17:41
  • A remarkable, incorrect assertion. It is very much a part of the JavaScript standard, unless you are referring to the creaky old ES3 standard implemented by IE <= 8. Should you need to support legacy browsers like that, there are polyfills aplenty, including those provided by es5-shim, which is also included in Modernizr, which I assume you are acquainted with and using. –  Nov 03 '14 at 18:03
  • In case you are interested, here is the spec reference: http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.17. –  Nov 03 '14 at 19:03
0

You could build the logic into your sort function. The idea would be that two numbers fall in numerical order, two strings fall in alpha order, and strings sort after numbers.

function sortfunc(a, b) {
    if (isNaN(a)) {
        if (isNaN(b)) { return a < b ? -1 :   +1; } 
        else          { return                +1; }
    } else {
        if (isNaN(b)) { return                -1; } 
        else          { return +a < +b ? -1 : +1; }
    }
}

document.writeln(['b', '1', '20', 'a', '10'].sort(sortfunc).join(' -- '));
 

Or, if you prefer, you could preconvert:

function toNumber(n) { return isNaN(n) ? a : +a; }

myArray
    .map(toNumber)
    .sort(function(a, b) { 
        return a < b ? -1 : +1; 
     });