python natsort:如何在字典列表中优先按字母排序并带版本号
假设我有这样一个列表:
my_list = [
{'id': 'Bear@1.0.1'}, {'id': 'Bear@5.5.1'}, {'id': 'Bear@10.0.9'}, {'id': 'Bear@5.1'},
{'id': 'Air@7.6'}, {'id': 'Air@8.7'}, {'id': 'Air@10.0.0'}, {'id': 'Air@1.0'}
]
我希望最终的列表先按照@前面的部分排序,然后再按照版本号排序。
我这样做:natsort.natsorted(my_list, key=itemgetter(*['id']), reverse=True)
我得到了以下结果:
[{'id': 'Bear@10.0.9'},
{'id': 'Bear@5.5.1'},
{'id': 'Bear@5.1'},
{'id': 'Bear@1.0.1'},
{'id': 'Air@10.0.0'},
{'id': 'Air@8.7'},
{'id': 'Air@7.6'},
{'id': 'Air@1.0'}]
我该怎么做才能让natsort工作,使得所有“Air”的项目都排在所有“Bear”的项目之前,同时仍然按照版本号排序(就像现在这样正确)?
2 个回答
0
先把这个自然排序的列表拿出来,然后只根据@符号前面的部分进行排序。这个排序是稳定的,所以版本的顺序不会被打乱。
ds = [{'id': 'Bear@10.0.9'},
{'id': 'Bear@5.5.1'},
{'id': 'Bear@5.1'},
{'id': 'Bear@1.0.1'},
{'id': 'Air@10.0.0'},
{'id': 'Air@8.7'},
{'id': 'Air@7.6'},
{'id': 'Air@1.0'}]
ds.sort(key=lambda d: d['id'].split('@')[0])
for d in ds:
print(d)
输出结果(在线尝试一下!):
{'id': 'Air@10.0.0'}
{'id': 'Air@8.7'}
{'id': 'Air@7.6'}
{'id': 'Air@1.0'}
{'id': 'Bear@10.0.9'}
{'id': 'Bear@5.5.1'}
{'id': 'Bear@5.1'}
{'id': 'Bear@1.0.1'}
0
我会使用一个自定义的比较函数,专门用来反向比较版本号。这样可以确保版本号的比较是正确的。我会用 natsort.natsort_keygen
来生成一个可以正确比较版本号的函数。
from operator import methodcaller, itemgetter
my_list = [
{'id': 'Bear@1.0.1'}, {'id': 'Bear@5.5.1'}, {'id': 'Bear@10.0.9'}, {'id': 'Bear@5.1'},
{'id': 'Air@7.6'}, {'id': 'Air@8.7'}, {'id': 'Air@10.0.0'}, {'id': 'Air@1.0'}
]
vkey = natsort.natsort_keygen()
# Python 2's three-way comparison function:
# x < y returns negative
# x == y returns zero
# x > y returns positive
#
# To reverse the comparison, swap the arguments.
def cmp(x, y):
return -1 if x < y else 0 if x == y else 1
def cmp_str(x, y):
splitter = operator.methodcaller('split', '@')
getter = operator.itemgetter('id')
x1, x2 = splitter(getter(x))
y1, y2 = splitter(getter(y))
return cmp(x1, y1) \
or cmp(vkey(y2), vkey(x2))
for x in sorted(my_list, key=functools.cmp_to_key(cmp_str)):
print(x)
输出结果:
{'id': 'Air@10.0.0'}
{'id': 'Air@8.7'}
{'id': 'Air@7.6'}
{'id': 'Air@1.0'}
{'id': 'Bear@10.0.9'}
{'id': 'Bear@5.5.1'}
{'id': 'Bear@5.1'}
{'id': 'Bear@1.0.1'}