Sort version-dotted number strings in Javascript?

前端 未结 14 1694
栀梦
栀梦 2020-12-05 15:01

I have an array of following strings:

[\'5.5.1\', \'4.21.0\', \'4.22.0\', \'6.1.0\', \'5.1.0\', \'4.5.0\'] 

...etc.

I need a soluti

相关标签:
14条回答
  • 2020-12-05 15:19

    This solution accounts for version numbers that might not be in the full, 3-part format (for example, if one of the version numbers is just 2 or 2.0 or 0.1, etc).

    The custom sort function I wrote is probably mostly what you're looking for, it just needs an array of objects in the format {"major":X, "minor":X, "revision":X}:

    var versionArr = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0'];
    var versionObjectArr = [];
    var finalVersionArr = [];
    /*
    split each version number string by the '.' and separate them in an
    object by part (major, minor, & revision).  If version number is not
    already in full, 3-part format, -1 will represent that part of the
    version number that didn't exist.  Push the object into an array that
    can be sorted.
    */
    for(var i = 0; i < versionArr.length; i++){
      var splitVersionNum = versionArr[i].split('.');
      var versionObj = {};
      switch(splitVersionNum.length){
        case 1:
          versionObj = {
            "major":parseInt(splitVersionNum[0]),
            "minor":-1,
            "revision":-1
          };
          break;
        case 2:
          versionObj = {
            "major":parseInt(splitVersionNum[0]),
            "minor":parseInt(splitVersionNum[1]),
            "revision":-1
          };
          break;
        case 3:
          versionObj = {
            "major":parseInt(splitVersionNum[0]),
            "minor":parseInt(splitVersionNum[1]),
            "revision":parseInt(splitVersionNum[2])
          };
      }
      versionObjectArr.push(versionObj);
    }
    
    //sort objects by parts, going from major to minor to revision number.
    versionObjectArr.sort(function(a, b){
      if(a.major < b.major) return -1;
      else if(a.major > b.major) return 1;
      else {
        if(a.minor < b.minor) return -1;
        else if(a.minor > b.minor) return 1;
        else {
          if(a.revision < b.revision) return -1;
          else if(a.revision > b.revision) return 1;
        }
      }
    });
    
    /*
    loops through sorted object array to recombine it's version keys to match the original string's value.  If any trailing parts of the version
    number are less than 0 (i.e. they didn't exist so we replaced them with
    -1) then leave that part of the version number string blank. 
    */
    for(var i = 0; i < versionObjectArr.length; i++){
      var versionStr = "";
      for(var key in versionObjectArr[i]){
        versionStr = versionObjectArr[i].major;
        versionStr += (versionObjectArr[i].minor < 0 ? '' : "." + versionObjectArr[i].minor);
        versionStr += (versionObjectArr[i].revision < 0 ? '' : "." + versionObjectArr[i].revision);
      }
      finalVersionArr.push(versionStr);
    }
    console.log('Original Array: ',versionArr);
    console.log('Expected Output: ',['4.5.0', '4.21.0', '4.22.0', '5.1.0', '5.5.1', '6.1.0']);
    console.log('Actual Output: ', finalVersionArr);

    0 讨论(0)
  • 2020-12-05 15:22

    If you are looking for a npm package to compare two semver version, https://www.npmjs.com/package/compare-versions is the one.

    Then you can sort version like this:

    // ES6/TypeScript
    import compareVersions from 'compare-versions';
    
    var versions = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0'];
    var sorted = versions.sort(compareVersions);
    
    0 讨论(0)
  • 2020-12-05 15:22

    If ES6 I do this:

    versions.sort((v1, v2) => {
      let [, major1, minor1, revision1 = 0] = v1.match(/([0-9]+)\.([0-9]+)(?:\.([0-9]+))?/);
      let [, major2, minor2, revision2 = 0] = v2.match(/([0-9]+)\.([0-9]+)(?:\.([0-9]+))?/);
      if (major1 != major2) return parseInt(major1) - parseInt(major2);
      if (minor1 != minor2) return parseInt(minor1) - parseInt(major2);
      return parseInt(revision1) - parseInt(revision2);
    });
    
    0 讨论(0)
  • 2020-12-05 15:23

    You can check in loop if values are different, return difference, else continue

    var a=['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0', '4.5.0'];
    
    a.sort(function(a,b){
      var a1 = a.split('.');
      var b1 = b.split('.');
      var len = Math.max(a1.length, b1.length);
      
      for(var i = 0; i< len; i++){
        var _a = +a1[i] || 0;
        var _b = +b1[i] || 0;
        if(_a === _b) continue;
        else return _a > _b ? 1 : -1
      }
      return 0;
    })
    
    console.log(a)

    0 讨论(0)
  • 2020-12-05 15:26

    Though slightly late this would be my solution;

    var arr = ["5.1.1","5.1.12","5.1.2","3.7.6","2.11.4","4.8.5","4.8.4","2.10.4"],
     sorted = arr.sort((a,b) => {var aa = a.split("."),
                                     ba = b.split(".");
                                 return +aa[0] < +ba[0] ? -1
                                                        : aa[0] === ba[0] ? +aa[1] < +ba[1] ? -1
                                                                                            : aa[1] === ba[1] ? +aa[2] < +ba[2] ? -1
                                                                                                                                : 1
                                                                                                              : 1
                                                                          : 1;
                                });
     console.log(sorted);

    0 讨论(0)
  • 2020-12-05 15:27

    You could split the strings and compare the parts.

    function customSort(data, order) {
    
      function isNumber(v) {
        return (+v).toString() === v;
      }
    
      var sort = {
        asc: function (a, b) {
          var i = 0,
            l = Math.min(a.value.length, b.value.length);
    
          while (i < l && a.value[i] === b.value[i]) {
            i++;
          }
          if (i === l) {
            return a.value.length - b.value.length;
          }
          if (isNumber(a.value[i]) && isNumber(b.value[i])) {
            return a.value[i] - b.value[i];
          }
          return a.value[i].localeCompare(b.value[i]);
        },
        desc: function (a, b) {
          return sort.asc(b, a);
        }
      }
      var mapped = data.map(function (el, i) {
        return {
          index: i,
          value: el.split('')
        };
      });
    
      mapped.sort(sort[order] || sort.asc);
      return mapped.map(function (el) {
        return data[el.index];
      });
    }
    
    var array = ['5.5.1', '4.21.0', '4.22.0', '6.1.0', '5.1.0'];
    
    console.log('sorted array asc', customSort(array));
    console.log('sorted array desc ', customSort(array, 'desc'));
    console.log('original array ', array);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

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