8

I have a version number with 3 digits as a String,

var version = "1.2.3";

and would like to compare it to another version. To see if version is newer than otherversion,

var otherVersion = "1.2.4";

How would you do it?

2
  • do you want to use the code to sort versions? Do you want to use it only for 3 digits? what about eg. "1.4.11" ? Commented May 11, 2010 at 11:07
  • 1
    Yes its to compare different versions of a javascript. So if its an old version, make update. At the moment its only one digit for each version number, but yes the ideal thing would be to support for example 1.4.11 Commented May 11, 2010 at 11:16

11 Answers 11

9

Pseudo:

  • Split both on .
  • Compare parts sequentially: Major -> Minor -> Rev (if part exist for both versions).
  • If oV[n] > v[n]: oV is greatest.
  • Else: Compare next subpart.

(See @arhorns answer for a elegant implementation)

Sign up to request clarification or add additional context in comments.

2 Comments

Missing items: "if no further subpart exists, version are identical" and possible after the splitting "assert both versions have the same number of parts".
Missing step two: convert strings to numbers so that "11" sorts after "2".
7

The problem with most of the submitted versions is they can't handle any number of version parts (eg. 1.4.2 .. 1.2 etc) and/or they have the requirement of the version part being a single digit, which is not that common actually.

Improved compareVersions() function

This function will return 1 if v1 is greater than v2, -1 if v2 is greater and 0 if the versions are equal (handy for custom sorting as well)

I'm not doing any error checking on the inputs.

function compareVersions (v1, v2)
{
    v1 = v1.split('.');
    v2 = v2.split('.');
    var longestLength = (v1.length > v2.length) ? v1.length : v2.length;
    for (var i = 0; i < longestLength; i++) {
        if (v1[i] != v2[i]) {
            return (v1 > v2) ? 1 : -1
        }
    }
    return 0; 
 }

7 Comments

Nice. var longestLength = Math.max(v1.length, v2.length);
@arnorhs: Just noticed that you already made an attempt at this. However, compareVersions('1.2.3', '1.2.3.0') will return -1, but I guess it should return 0. You may want to use the || operator to default an undefined to 0 in (v1[i] != v2[i]). In addition, you have a typo in i < longestLenght.
this worked perfectly. thanks! spelling error on longestLenght btw ;)
@arnorhs: In addition, compareVersions('1.2.3', '1.2.10') will also return 1 when it should return -1. You need parseInt() to fix this.
@heffaklump: It won't work perfectly in all situations, unless the issues I mentioned in the two comments above are addressed.
|
5

You may want to use the following implementation (based on jensgram's solution):

function isNewer(a, b) {
   var partsA = a.split('.');
   var partsB = b.split('.');
   var numParts = partsA.length > partsB.length ? partsA.length : partsB.length;
   var i;

   for (i = 0; i < numParts; i++) {
      if ((parseInt(partsB[i], 10) || 0) !== (parseInt(partsA[i], 10) || 0)) {
         return ((parseInt(partsB[i], 10) || 0) > (parseInt(partsA[i], 10) || 0));
      }
   }

   return false;
}

console.log(isNewer('1.2.3', '1.2.4'));    // true
console.log(isNewer('1.2.3', '1.2.0'));    // false
console.log(isNewer('1.2.3', '1.2.3.1'));  // true
console.log(isNewer('1.2.3', '1.2.2.9'));  // false
console.log(isNewer('1.2.3', '1.2.10'));   // true

Note that the use of parseInt() is necessary, because otherwise the last test would return false: "10" > "3" returns false.

4 Comments

for each (i in aVersion) ? For an array? Why?
why error when the versions have different number of parts? Why not have it support all?
@arnorhs: There you go :) ... @npup: Fixed.
I've put your implementation in and it works very good :) thanks mate! Nice finding the bug with 10, hadnt thought about that
3

If indeed you only have a single digit in each part why not just use straight comparison?

>>> var version = "1.2.3"; var otherVersion = "1.2.4"; version < otherVersion
true

It seems also to work with abbreviated versions:

>>> '1.2' > '1.2.4'
false
>>> '1.3' > '1.2.4'
true

2 Comments

Wouldn't you want the comparison to support more than a single digit version part and wouldn't you want it to be able to compare "1.2" against "1.2.4" ?
@ahorhs: I have a version number with 3 digits as a String, Nevertheless, '1.2' > '1.2.3' comparison works perfectly fine.
1

With one of the comparison operators.

"1.2.3" > "1.2.4" //false

"1.2.3" < "1.2.4" //true

4 Comments

"1.2.3" < "1.2.10" // false but should be true
Your example has four digits. The question explicitly mentions a three digit string.
It's still well possible that four digits occur. A very elegant but not stable enough solution IMO.
That's true, but it's just as likely, and just as erroneous, that one of the version strings could be "foo.bar.wibble.wobble", "044.0x99.6" or null. Most of the more complicated solutions here are equally as unstable.
1
function VersionValue(var str)
{
var tmp = str.split('.');
return (tmp[0] * 100) + (tmp[1] * 10) + tmp[2];
}

if (VersionValue(version) > VersionValue(otherVersion))...

for example

2 Comments

This would actually result in the version 0.1.1 being less than 0.0.15. Your answer needs to be more accurate, I think.
true but my basic point is that he could just split it and do the calcs.. what algorithm he uses is up to him
1

Since I'm bored, here's an approach similar to our decimal system (tens, hundreds, thousands, etc) which uses a regex callback instead of a loop:

function compareVersion(a, b) {
    var expr = /\d+/g, places = Math.max(a.split(expr).length, b.split(expr).length);
    function convert(s) {
        var place = Math.pow(100, places), total = 0;
        s.replace(expr,
            function (n) {
                total += n * place;
                place /= 100;
            }
        );
        return total;
    };

    if (convert(a) > convert(b)) {
        return a;
    }

    return b;
}

It returns the greater version, e.g.:

compareVersion('1.4', '1.3.99.32.60.4'); // => 1.4

Comments

1
function isCorrectVersion(used,required){
    var used = parseFloat("0."+used.replace(/\./gi,""));
    var required = parseFloat("0."+required.replace(/\./gi,""));

    return (used < required) ? false : true;
}

I use this to compare jQuery functions and it seems to work fine, also comparing for example 1.4 with 1.4.1 or 1.4.1 with 1.4.11.

Comments

1

I couldnt find an answer that returns 1, 0 or -1 and takes care of both trailing .0 and two digit partials, so here goes. This should support all cases where all the partials are numbers (see the tests at the bottom).

/*
 * Returns 1 if v1 is newer, -1 if v2 is newer and 0 if they are equal.
 * .0s at the end of the version will be ignored.
 *
 * If a version evaluates to false it will be treated as 0.
 *
 * Examples:
 * compareVersions ("2.0", "2") outputs 0,
 * compareVersions ("2.0.1", "2") outputs 1,
 * compareVersions ("0.2", "0.12.1") outputs -1,
 *
 */
function compareVersions (version1, version2) {
  var version1 = version1 ? version1.split('.') : ['0'],
      version2 = version2 ? version2.split('.') : ['0'],
      longest = Math.max(version1.length, version2.length);

  for (var i = 0; i < longest; i++) {
    /*
     * Convert to ints so that we can compare two digit parts
     * properly. (Otherwise would "2" be greater than "12").
     *
     * This returns NaN if the value is undefined, so we check for
     * NaN later.
     */
    var v1Part = parseInt(version1[i]),
        v2Part = parseInt(version2[i]);

    if (v1Part != v2Part) {

      // version2 is longer
      if (isNaN(v1Part)) {
        /*
         * Go through the rest of the parts of version 2. If it is only zeros,
         * consider the versions equal, otherwise consider version 2 as newer.
         */
        for (var j = i; j < longest; j++) {
          if (parseInt(version2[j]) != 0) return -1;
        }

      // version1 is longer
      } else if (isNaN(v2Part)) {
        for (var j = i; j < longest; j++) {
          if (parseInt(version1[j]) != 0) return 1;
        }

      // versions are equally long
      } else {
        return (v1Part > v2Part) ? 1 : -1;
      }
      return 0;
    }
  }
  return 0;
}

console.log(compareVersions("1", "1") === 0);
console.log(compareVersions("1.1", "1") === 1);
console.log(compareVersions("1.1.1", "1") === 1);
console.log(compareVersions("1", "1.1.1") === -1);
console.log(compareVersions("0.3", "0.3.0.0.1") === -1);
console.log(compareVersions("0.3", "0.3.0") === 0);
console.log(compareVersions("0.3.0.0.1", "0.3") === 1);
console.log(compareVersions("0.3.0", "0.3") === 0);
console.log(compareVersions("0.12", "0.2") === 1);
console.log(compareVersions("0.2", "0.12") === -1);
console.log(compareVersions("0.12.0", "0.2") === 1);
console.log(compareVersions("0.02.0", "0.2") === 0);
console.log(compareVersions("0.01.0", "0.2") === -1);

Comments

0

Note, that none of these solutions will knowingly return the right result for things like 0.9beta or 1.0 RC 1. It is, however, handled quite intuitively in PHP: http://de3.php.net/manual/en/function.version-compare.php and there is a JS port of this: http://phpjs.org/functions/version_compare (I don't claim this to be very nice or efficient, just kind of 'complete').

Comments

0

Maybe like this (quickie)?

function isNewer(s0, s1) {
    var v0 = s0.split('.'), v1 = s1.split('.');
    var len0 = v0.length, len1=v1.length;
    var temp0, temp1, idx = 0;
    while (idx<len0) {
        temp0 = parseInt(v0[idx], 10);
        if (len1>idx) {
            temp1 = parseInt(v1[idx], 10);
            if (temp1>temp0) {return true;}
        }
        idx += 1;
    }
    if (parseInt(v0[idx-1], 10)>parseInt(v1[idx-1], 10)) {return false;}
    return len1 > len0;
}
var version = "1.2.3";
var otherVersion = "1.2.4";

console.log('newer:'+(isNewer(version, otherVersion)));

It takes care of different number of parts, but it works only with numbers between the dots though.

5 Comments

It seems awefully long, complicated and only supports versions with three version parts
Heh, it's not complicated. It's just a loop. It surely DOES support more than three parts (that's what makes it a bit longer than some other suggestions here). And IMO it's not much longer han it has to be, taking into consideration that it has to 1) compare each field till it finds out the second is "newer" (then we're done) and else 2) if second string has more fields, then it is also newer.
temp1 and temp2 should be temp0 and temp1 for consistency. Or preferably something describing, like num0 and num1.
@npup: You may want to use parseInt(x, 10) because without specifying the base, isNewer("1.2.03", "1.2.08") returns false, while isNewer("1.2.03", "1.2.07") returns true.
Good idea, thanks! One never knows what stuff people feed you these days.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.