Sort Array of numeric & alphabetical elements (Natural Sort)

后端 未结 8 1039
独厮守ぢ
独厮守ぢ 2020-12-03 14:48

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 ...

相关标签:
8条回答
  • 2020-12-03 14:56

    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".

    0 讨论(0)
  • 2020-12-03 14:57

    If you have only alphabetical and integer items, you can stick with simple code:

    var arr = [1,5,"ahsldk",10,55,3,2,7,8,1,2,75,"abc","huds"];
    arr.sort(function(a, b)
    {
        if (a == b)
            return 0;
    
        var n1 = parseInt(a, 10);
        var n2 = parseInt(b, 10);
        if (isNaN(n1) && isNaN(n2)) {
            //both alphabetical
            return (a > b) ? 1 : 0;
        }
        else if (!isNaN(n1) && !isNaN(n2)) {
            //both integers
            return (n1 > n2) ? 1 : 0;
        }
        else if (isNaN(n1) && !isNaN(n2)) {
            //a alphabetical and b is integer
            return 1;
        }
    
        //a integer and b is alphabetical
        return 0;
    });
    

    Working example: http://jsfiddle.net/25X2e/

    0 讨论(0)
  • 2020-12-03 14:57

    I knew the following way also which might sort the array alphanumerically order.

    const arr = [1, 5, "ahsldk", 10, 55, 3, 2, 7, 8, 1, 2, 75, "abc", "huds"];
    arr.sort((a, b) => a - b || a.toString().localeCompare(b.toString()));
    console.log(arr)

    0 讨论(0)
  • 2020-12-03 14:58

    If you can always assume numbers and strings of unmixed alphas, I would just divide and conquer. slice out numbers into a new array using typeof. Sort both independently and then just join the two arrays.

    0 讨论(0)
  • 2020-12-03 15:03

    // Most natural sorts are for sorting strings, so file2 is sorted before file10.

    If you are mixing in actual numbers you need to sort them to the front of the array, because negative numbers and digits separated by hyphens are a pain to interpret. Strings with leading zeroes need to be careful, so part002 will sort before part010.

    var natSort=function(as, bs) {
        var a, b, a1, b1,
        rx=  /(\d+)|(\D+)/g, rd= /\d/, rz=/^0/;
        if(typeof as=='number' || typeof bs=='number'){
            if(isNaN(as))return 1;
            if(isNaN(bs))return -1;
            return as-bs;
        }
        a= String(as).toLowerCase();
        b= String(bs).toLowerCase();
        if(a=== b) return 0;
        if(!(rd.test(a) && rd.test(b))) return a> b? 1: -1;
        a= a.match(rx);
        b= b.match(rx);
        while(a.length && b.length){
            a1= a.shift();
            b1= b.shift();
            if(a1!== b1){
                if(rd.test(a1) && rd.test(b1)){
                    return a1.replace(rz,'.0')- b1.replace(rz,'.0');
                }
                else return a1> b1? 1: -1;
            }
        }
        return a.length - b.length;
    }
    
    array.sort(natSort)
    
    0 讨论(0)
  • 2020-12-03 15:07

    You could do this in one line using String.prototype.localCompare() and get the result you are looking for. Note that the numeric collation option is enabled.

    var arr = [1,5,"ahsldk",10,55,3,2,7,8,1,2,75,"abc","huds"];
    
    arr.sort((a,b) => ("" + a).localeCompare(b, undefined, {numeric: true}));
    
    console.log(arr);
    // [1, 1, 2, 2, 3, 5, 7, 8, 10, 55, 75, "abc", "ahsldk", "huds"]

    Maybe add some logic to handle nulls.

    0 讨论(0)
提交回复
热议问题