Sorting a list of dot-separated numbers, like software versions

Question:

I have a list containing version strings, such as things:

versions_list = ["1.1.2", "1.0.0", "1.3.3", "1.0.12", "1.0.2"]

I would like to sort it, so the result would be something like this:

versions_list = ["1.0.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]

The order of precedence for the digits should obviously be from left to right, and it should be descending. So 1.2.3 comes before 2.2.3 and 2.2.2 comes before 2.2.3.

How do I do this in Python?

Asked By: Zack

||

Answers:

Split each version string to compare it as a list of integers:

versions_list.sort(key=lambda s: map(int, s.split('.')))

Gives, for your list:

['1.0.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3']

In Python3 map no longer returns a list, So we need to wrap it in a list call.

versions_list.sort(key=lambda s: list(map(int, s.split('.'))))

The alternative to map here is a list comprehension. See this post for more on list comprehensions.

versions_list.sort(key=lambda s: [int(u) for u in s.split('.')])
Answered By: Eli Bendersky

You can also use distutils.version module of standard library:

from distutils.version import StrictVersion
versions = ["1.1.2", "1.0.0", "1.3.3", "1.0.12", "1.0.2"]
versions.sort(key=StrictVersion)

Gives you:

['1.0.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3']

It can also handle versions with pre-release tags, for example:

versions = ["1.1", "1.1b1", "1.1a1"]
versions.sort(key=StrictVersion)

Gives you:

["1.1a1", "1.1b1", "1.1"]

Documentation: https://github.com/python/cpython/blob/3.2/Lib/distutils/version.py#L101

Answered By: andreypopp

natsort proposes “natural sorting”; wich works very intuitively (in Python 3)

from natsort import natsorted
versions = ["1.1.2", "1.0.0", "1.3.3", "1.0.12", "1.0.2"]
natsorted(versions)

gives

['1.0.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3']

but it works as well on complete package names with version number:

versions = ['version-1.9', 'version-2.0', 'version-1.11', 'version-1.10']
natsorted(versions)

gives

['version-1.9', 'version-1.10', 'version-1.11', 'version-2.0']
Answered By: Chris Maes

I also solved this question using Python, although my version does some extra things, here is my code:

def answer(l):
    list1 = [] # this is the list for the nested strings
    for x in l:
        list1.append(x.split("."))
    list2 = [] # this is the same list as list one except everything  is an integer in order for proper sorting
    for y in list1:
        y = list(map(int, y))
        list2.append(y)
    list3 = sorted(list2) #this is the sorted list of of list 2
    FinalList = [] # this is the list that converts everything back to the way it was
    for a in list3:
        a = '.'.join(str(z) for z in a)
        FinalList.append(a)
    return FinalList

For versions there exist three things; Major, Minor, and the revision. What this does is that it organises it so that '1' will come before '1.0' which will come before '1.0.0'. Also, another plus, no need to import any libraries incase you don’t have them, and it works with old versions of Python, this one was specifically meant for Version 2.7.6. Anyway, here are a few examples:

Inputs:
    (string list) l = ["1.1.2", "1.0", "1.3.3", "1.0.12", "1.0.2"]
Output:
    (string list) ["1.0", "1.0.2", "1.0.12", "1.1.2", "1.3.3"]

Inputs:
    (string list) l = ["1.11", "2.0.0", "1.2", "2", "0.1", "1.2.1", "1.1.1", "2.0"]
Output:
    (string list) ["0.1", "1.1.1", "1.2", "1.2.1", "1.11", "2", "2.0", "2.0.0"]

If you have any questions, just comment on the answer!

Answered By: Sarim Aleem

I have an answer to this question. Unlike other codes, my code is bit lengthy and has more time and space complexity.

The advantage of my code is that, this code just uses built in functions and could be of a great exercise to practice and master looping concept for the beginners.

x=["1.11.0","2.0.0","1.2.1","1.1.1",'1.2.0']                    #Driver List 
le=len(x)                                                       #Length of the given driver list
x2=[]                                                           #list to store the values of x after splitting 
mapping=[]                                                      #list to store the values after type converstion 
map1=[]                                                         #list to store the values after sorting 
final=[]                                                        #list to store the final value after concatenation 

#Loop for splitting the given values with respect to '.'

for i in x:
    y=i.split('.')
    x2.append(y)
#print(x2)

#Loop for mapping the string value to integer value. This conversion overcomes the issue we have 
#With simple sorting technique as given in the question, and helps us in sorting the versions in our desired format

for i in range(0,le,1):
    mapped=list(map(int,x2[i]))                                 # mapped is a return value for the map()
    mapping.append(mapped)                                      # mapped value which is now a int, is appended to mapping array
#print(mapping)

mapping.sort()                                                  #Sorts the elements present in mapping array


#Loop to re-convert all the sorted integer value to string type

for i in mapping:
    mapp=list(map(str,i))                                       # mapp is a return value for the map()
    map1.append(mapp)                                           # mapp is now a str, gets appended to map1 array
#print(mapp)

#Loop to cancatenate the str values in mapp array with the '.'
#This converts the individual str type values in mapp array to its original form, like those in DriverList 

for i in range(0,le,1):
    for j in range(0,1,1):
        h=map1[i][j]+"."+map1[i][j+1]+"."+map1[i][j+2]
        final.append(h)

#Loop to Print the desired answer

for i in final:
    print(i,end='  ')



#For Better understanding of this program, uncomment the print statements in line 13, 21, 31.

The Output for the above code will be like:

1.1.1  1.2.0  1.2.1  1.11.0  2.0.0

The above is the sorted versions given in the driver list. Hope my code is clear. Pls feel free to ask any doubts if you have in comment section

Answered By: DrinkandDerive

I think meanwhile, one would use packaging.version for that.

Example:

from packaging.version import parse as parseVersion
versions = ['3.1', '0.7.1', '3.4.1', '0.7.7', '0.7.2', '3.3', '3.4.0', '0.7'
            '0.7.5', '0.7.6', '3.0', '3.3.1', '0.7.3', '3.2', '0.7.4']
versions.sort(key = parseVersion)

Output:

['0.7', '0.7.1', '0.7.2', '0.7.3', '0.7.4', '0.7.5', '0.7.6',
 '0.7.7', '3.0', '3.1', '3.2', '3.3', '3.3.1', '3.4.0', '3.4.1']
Answered By: Tobias Leupold
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.