Python实现含字母数字端口字段的字典列表正确排序
MAC-端口映射列表端口字段排序问题
问题场景
开发中需要对存储网络设备MAC地址与端口映射关系的字典列表执行排序操作,初始实现代码如下:
from pprint import pprint output_list = [{'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'}, {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}] mac_list = sorted(output_list, key=lambda d: "/".join([x for x in d['port'].split("/")])) pprint(mac_list)
由于port字段是字母与数字混合的字符串格式,默认字符串逐位比较的排序逻辑会导致数字段排序错乱,例如Gi1/0/10会排在Gi1/0/5之前,Python 3.10环境下实际运行输出结果不符合预期:
"C:\Program Files\Python310\python.exe" "C:/Scripts/Python/test1.py" [{'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'}, {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}] Process finished with exit code 0
预期按端口分段数值逻辑排序,效果如下:
[{'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'}, {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}]
故障原因
初始实现直接将拆分后的端口段拼接为字符串作为排序key,使用的是字符串字典序比较规则:逐字符对比ASCII值,数字部分也按单个字符比较。例如字符串"10"的首字符是'1',ASCII值小于字符'5',因此会出现10排在5前面的错乱问题。
实现方案
排序时将端口字符串拆分为「接口类型前缀+多段数字」的结构:字母前缀保留字符串比较逻辑,所有数字段转为整数做数值比较,通过元组逐段对比即可得到符合端口逻辑的排序结果。
可直接运行的实现代码如下:
import re from pprint import pprint def get_port_sort_key(port_str: str): # 拆分接口类型字母前缀和后续数字部分 prefix_match = re.match(r'([A-Za-z]+)(.*)', port_str) if not prefix_match: return (port_str,) interface_prefix, num_segment_part = prefix_match.groups() # 数字部分按/拆分后转整数,避免字符串排序的数字错乱问题 num_segments = [int(seg) for seg in num_segment_part.split('/')] return (interface_prefix, *num_segments) output_list = [{'mac': '0123.4567.89ab', 'port': 'Gi1/0/10'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/5'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/48'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/1'}, {'mac': '0123.4567.89ab', 'port': 'Gi1/0/6'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/4'}, {'mac': '0123.4567.89ab', 'port': 'Gi2/0/13'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/9'}, {'mac': '0123.4567.89ab', 'port': 'Gi8/0/8'}, {'mac': '0123.4567.89ab', 'port': 'Te1/1/1'}] mac_list = sorted(output_list, key=lambda item: get_port_sort_key(item['port'])) pprint(mac_list)
运行上述代码即可输出预期的排序结果,该方案兼容常见的Fa(百兆)、Gi(千兆)、Te(万兆)等不同前缀的网络端口格式,数字段长度不固定时也能正常按数值排序。
内容的提问来源于stack exchange,提问作者Ryan Bell
相关产品推荐
相关产品推荐

