Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort Array of numeric & alphabetical elements (Natural Sort)

Suppose I have an array

var arr = [1,5,"ahsldk",10,55,3,2,7,8,1,2,75,"abc","huds"];

and I try sorting it, I get something like ...

[1, 1, 10, 2, 2, 3, 5, 55, 7, 75, 8, "abc", "ahsldk", "huds"]

notice 10 is before 2, how can I have something more like

[1,1,2,2,3,5 ..., "abc", "ahs...",...]
like image 819
Jiew Meng Avatar asked Dec 07 '10 03:12

Jiew Meng


People also ask

How do you sort numbers in an array?

sort() method is used to sort the array elements in-place and returns the sorted array. This function sorts the elements in string format. It will work good for string array but not for numbers. For example: if numbers are sorted as string, than “75” is bigger than “200”.

How do I arrange numbers in ascending order in JavaScript?

JavaScript Array sort() The sort() sorts the elements as strings in alphabetical and ascending order.

How does numeric sort work in JavaScript?

Numeric SortBy default, the sort() function sorts values as strings. This works well for strings ("Apple" comes before "Banana"). However, if numbers are sorted as strings, "25" is bigger than "100", because "2" is bigger than "1". Because of this, the sort() method will produce incorrect result when sorting numbers.


1 Answers

Short and sweet, per the original question:

var arr = [1,5,"ahsldk",10,55,3,2,7,8,1,2,75,"abc","huds"];
arr.sort(function(a,b){
  var a1=typeof a, b1=typeof b;
  return a1<b1 ? -1 : a1>b1 ? 1 : a<b ? -1 : a>b ? 1 : 0;
});
// [1, 1, 2, 2, 3, 5, 7, 8, 10, 55, 75, "abc", "ahsldk", "huds"]

(Sort first by type, then by value.)


A more-full-featured natural sort:

var items = ['a1c', 'a01', 'a1', 'a13', 'a1a', 'a1b', 'a3b1', 'a1b0',
             'a1b3', 'a1b1', 'dogs', 'cats', 'hogs', 'a2', '2', '20',
             1, 13, 1.1, 1.13, '1.2', 'a'];
 
console.log(naturalSort(items))
 
function naturalSort(ary, fullNumbers) {
  var re = fullNumbers ? /[\d\.\-]+|\D+/g : /\d+|\D+/g;

  // Perform a Schwartzian transform, breaking each entry into pieces first
  for (var i=ary.length;i--;)
    ary[i] = [ary[i]].concat((ary[i]+"").match(re).map(function(s){
      return isNaN(s) ? [s,false,s] : [s*1,true,s];
    }));

  // Perform a cascading sort down the pieces
  ary.sort(function(a,b){
    var al = a.length, bl=b.length, e=al>bl?al:bl;
    for (var i=1;i<e;++i) {
      // Sort "a" before "a1"
      if (i>=al) return -1; else if (i>=bl) return 1;
      else if (a[i][0]!==b[i][0])
        return (a[i][1]&&b[i][1]) ?        // Are we comparing numbers?
               (a[i][0]-b[i][0]) :         // Then diff them.
               (a[i][2]<b[i][2]) ? -1 : 1; // Otherwise, lexicographic sort
    }
    return 0;
  });

  // Restore the original values into the array
  for (var i=ary.length;i--;) ary[i] = ary[i][0];
  return ary;
}

With naturalSort, pass true as the second parameter if you want "1.13" to sort before "1.2".

like image 158
Phrogz Avatar answered Oct 13 '22 22:10

Phrogz