python natsort:如何在字典列表中优先按字母排序并带版本号

-1 投票
2 回答
45 浏览
提问于 2025-04-13 14:58

假设我有这样一个列表:

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'}

撰写回答