晚上翻手机,看见一道网友发的python面试题求助帖,当时简单扫一眼就跳过了,但下来仔细想想觉得还蛮有趣,开电脑梳理下思路,因为没有官方答案,所以大家可以一起来做做,其中涉及的python知识点还是蛮多的。
题目内容
一个标准的版本需要涵盖,大版本.小版本.补丁版,各版本之间使用英文点符号分隔,且每个版本取值范围均为0~99。
现有一批产品版本号列表,需要过滤掉不符合要求的内容后,将版本号通过sorted进行升序排列。
题目分析
初看此题,给人的感觉有些好笑,居然要告诉大家使用sorted进行排序,难道是生怕谁不知道这个函数吗?
但当随便验证两个用例发现,sorted的默认排序存在BUG。
sorted(['1.3.0','1.1.0','1.2.0']) >>> ['1.1.0', '1.2.0', '1.3.0'] # 错误的默认排序 sorted(['1.30.0','1.4.0','1.2.0']) >>> ['1.2.0', '1.30.0', '1.4.0']
直接使用字符串进行排序,默认是按位对比每个版本号,然后进行排序,这导致了1.30.0 < 1.4.0的BUG。
仔细想想,面试官想考察的应该是sorted的自定义排序方法。那么该如何正确的比较所有版本号,又能同时过滤掉错误的版本号呢?
过滤版本号
考虑到版本号的特殊性,最简单的过滤方法,必然是正则了:
import re pattern = re.compile(r'^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}') if not pattern.match(version): raise ValueError("error version [%s],the version type must be [xx.xx.xx]" % version)
当然这里是我们验证的操作方式,排序时当然不能抛出异常了。
版本号比较
既然每个版本号的取值范围在0-99之间,那么熟悉数学的我们,是否有了思路?我们按照百进制的方式,来统计版本号,不就能轻易的达到目的么?就拿刚才的1.30.0和1.4.0来举例如下:
版本号 | 大版本(10000) | 小版本(100) | 补丁版本(1) | 总计 |
1.30.0 | 10000 | 3000 | 0 | 13000 |
1.4.0 | 10000 | 400 | 0 | 10400 |
2.1.0 | 20000 | 100 | 0 | 20100 |
最终代码
# -*- coding: utf-8 -*- # @微信号 : King_Uranus # @公众号 : 清风Python # @GitHub : https://github.com/BreezePython # @Date : 2020/11/04 22:48:33 # @Software : PyCharm # @version :Python 3.7.8 # @File : compare_version.py import re class CompareVersion: def __init__(self, version_list): self.versions = version_list self.error_version_num = 0 def com_version(self, version): sum_version = 0 version_weights = [10000, 100, 1] pattern = re.compile(r'^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}') if not pattern.match(version): self.error_version_num += 1 return -1 version_list = version.split('.') for index, small_version in enumerate(version_list): sum_version += version_weights[index] * int(small_version) return sum_version def sort_version(self): sorted_version = sorted(self.versions, key=lambda x: self.com_version(x)) return sorted_version[self.error_version_num:] if __name__ == '__main__': versions = ['0.0.0', '99.99.99', '100.0.1', '1.0.-1', '1.1.99', '2.10.1', '2.9.10', '999', '10-0.1'] main_class = CompareVersion(versions) print(main_class.sort_version()) output: ['0.0.0', '1.1.99', '2.9.10', '2.10.1', '99.99.99']
在sorted遍历过程中,每当发现一个错误版本号,我们就将error_version_num加一,并返回-1,这样当最终排序后,将切片的排序结果返回,就达到了最终的目的。
当然了,这只是我一时兴起的抛砖引玉答案,期待大家给出更好的作答。