在Python中对版本号列表进行排序 - Tinsley's blog

/ 0评 / 6

对于这样一个记录纯数字版本号字符串的Python list:

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

需要对其依据版本号大小进行排序.

相比于手动实现算法, 这里记录三种更tricky的方式.

本文的解题方法均来自于这个Stack Overflow问题: Sorting a list of dot-separated numbers, like software versions


使用 lambda&map

首先介绍我觉得实现最优雅的函数式思维的解决办法.

我们知道Python list的sort()方法可以接收一个参数key. key可以是一个函数, 对于list中的每一个元素, 都会在排序前对其执行key所定义的函数, 将执行结果作为排序的依据. 而lambda允许我们定义一个匿名函数作为key的值.

在此前提下, 我们可以想到, 如果将每一个版本号字符串, 如"1.1.2", 都转换成[1, 1, 2]这样的[int]格式, 这样一来, Python list的sort()方法会自动根据版本号的各个位进行依次排序.

比如给定这样一个list l:

l = [[1,1,2], [1,0,0], [1,3,3], [1,0,12], [1,0,2]]

对其直接使用sort()方法:

l.sort()
print l
# 输出为
[[1, 0, 0], [1, 0, 2], [1, 0, 12], [1, 1, 2], [1, 3, 3]]

而由"1.1.2"转换为[1, 1, 2]的过程, 可以用map函数来实现:

map(int, '1.1.2'.split('.'))

所以组合起来:

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

将会输出排序后的版本号列表:

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

需要注意的是, 由于在Python3中, map不再返回一个list, 所以我们需要在外面包一层list方法:

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

如果很难理解map的函数式思想, 也可以直接使用Python的for ... in ...语法:

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

这个解决方法使用到lambdamap, 可以说是相当Haskell了~


使用 distutils.version

对于Python这门语言, 我对它的印象一直是:

我能想到的日常需求, 肯定已经都有人帮我造好轮子了

不出所料地, Python标准库中的distutils.version包, 可以轻易地帮助我们实现版本的排序:

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)
print versions
# 输出
['1.0.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3']

甚至对于预发布的版本也不在话下:

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

其他的使用方法可以参阅它的文档: https://github.com/python/cpython/blob/3.2/Lib/distutils/version.py#L101


使用natsort

类似地, 在Python3环境下, natsort包也可以实现同样的需求:

from natsort import natsorted
versions = ["1.1.2", "1.0.0", "1.3.3", "1.0.12", "1.0.2"]
natsorted(versions)
print versions
# 输出
['1.0.0', '1.0.2', '1.0.12', '1.1.2', '1.3.3']

对于完整的版本字符串, natsort也可以很好地完成排序:

versions = ['version-1.9', 'version-2.0', 'version-1.11', 'version-1.10']
natsorted(versions)
print versions
# 输出
['version-1.9', 'version-1.10', 'version-1.11', 'version-2.0']

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注