I want to write a cmp
-like function which compares two version numbers and returns -1
, 0
, or 1
based on their compared valuses.
-1
if version A is older than version B0
if version A and B are equivalent1
if version A is newer than version BEach subsection is supposed to be interpreted as a number, therefore 1.10 > 1.1.
Desired function outputs are
mycmp('1.0', '1') == 0
mycmp('1.0.0', '1') == 0
mycmp('1', '1.0.0.1') == -1
mycmp('12.10', '11.0.0.0.0') == 1
...
And here is my implementation, open for improvement:
def mycmp(version1, version2):
parts1 = [int(x) for x in version1.split('.')]
parts2 = [int(x) for x in version2.split('.')]
# fill up the shorter version with zeros ...
lendiff = len(parts1) - len(parts2)
if lendiff > 0:
parts2.extend([0] * lendiff)
elif lendiff < 0:
parts1.extend([0] * (-lendiff))
for i, p in enumerate(parts1):
ret = cmp(p, parts2[i])
if ret: return ret
return 0
I'm using Python 2.4.5 btw. (installed at my working place ...).
Here's a small 'test suite' you can use
assert mycmp('1', '2') == -1
assert mycmp('2', '1') == 1
assert mycmp('1', '1') == 0
assert mycmp('1.0', '1') == 0
assert mycmp('1', '1.000') == 0
assert mycmp('12.01', '12.1') == 0
assert mycmp('13.0.1', '13.00.02') == -1
assert mycmp('1.1.1.1', '1.1.1.1') == 0
assert mycmp('1.1.1.2', '1.1.1.1') == 1
assert mycmp('1.1.3', '1.1.3.000') == 0
assert mycmp('3.1.1.0', '3.1.2.10') == -1
assert mycmp('1.1', '1.10') == -1
How about using Python's distutils.version.StrictVersion
?
>>> from distutils.version import StrictVersion
>>> StrictVersion('10.4.10') > StrictVersion('10.4.9')
True
So for your cmp
function:
>>> cmp = lambda x, y: StrictVersion(x).__cmp__(y)
>>> cmp("10.4.10", "10.4.11")
-1
If you want to compare version numbers that are more complex distutils.version.LooseVersion
will be more useful, however be sure to only compare the same types.
>>> from distutils.version import LooseVersion, StrictVersion
>>> LooseVersion('1.4c3') > LooseVersion('1.3')
True
>>> LooseVersion('1.4c3') > StrictVersion('1.3') # different types
False
LooseVersion
isn't the most intelligent tool, and can easily be tricked:
>>> LooseVersion('1.4') > LooseVersion('1.4-rc1')
False
To have success with this breed, you'll need to step outside the standard library and use setuptools's parsing utility parse_version
.
>>> from pkg_resources import parse_version
>>> parse_version('1.4') > parse_version('1.4-rc2')
True
So depending on your specific use-case, you'll need to decide whether the builtin distutils
tools are enough, or if it's warranted to add as a dependency setuptools
.