Python:在OrderedDict中使用自定义比较器进行排序

时间:2016-06-25 20:46:58

标签: python

我有一本字典,其中包含以下内容:

dict = {'P1' :361 , 'P2' : 361, 'P3' : 391, 'P6' : 361, 'P4':361, 'P5' :361}

需要根据值按降序排序。对于任何给定项目,如果该值与要比较的项目相同,则按键的升序排序。因此,dict的结果值应为此。

{'P3' : 391 , 'P1' : 361, 'P2': 361, 'P4': 361, 'P5': 361,'P6' : 361}

我使用它完成了第一部分:

sorted_dict = OrderedDict(sorted(dict.items(), key=lambda t: t[1],reverse=True))

然而,我不确定如何超越这一点。我假设比较器功能通常可以是这样的

def comparator(item1,item2):
    if item1.value() == item2.value():
        if item1.key()<item2.key():
            return -1
        if item1.key()>item2.key():
            return 1
        if item1.key() == item2.key():
            return 0
    if item1.value() < item2.value():
        return -1
    if item1.value() > item2.value():
        return 1

我不确定如何实现这一点。请原谅我的天真,我是Python的初学者,对语言中的编程结构知之甚少。

2 个答案:

答案 0 :(得分:2)

您可以使用稍微不同的lambda表达式作为排序键。

sorted_dict = OrderedDict(sorted(dict.items(), key=lambda x: (-x[1], x[0])))

<强>输出

OrderedDict([('P3', 391), ('P1', 361), ('P2', 361), ('P4', 361), ('P5', 361), ('P6', 361)])

提供key正在提供一个函数来在比较之前转换每个项目。所以在这里,匿名lambda函数提供了用于排序的序列转换 - 通过依次比较每个元素对序列进行排序。所以我们按数字的负数排序(反转自然上升 - &gt;下降),如果比较相等我们继续进行排序的字符串,这通常按照你想要的方式排序(至少提供的样本)。如果字典排序不能为您提供预期结果,则可能需要在字符串中使用string natural sorting来获取更大的数字。

答案 1 :(得分:1)

如果按键不能保留所有单个数字并且您不想要字典排序,那么您需要添加更多逻辑:

d = {'P1000': 361, 'P200': 361, 'P3': 391, 'P6': 361, 'P4': 361, 'P5': 361,"P100":361}
import re

patt = re.compile("[^\d]")


def cmp(x):
     letts = patt.search(x).group()
     return patt.search(x).group(), int(x[len(letts):])

您可以使用以下示例查看不同的行为:

In [1]: d = {'P1000': 361, 'P200': 361, 'P3': 391, 'P6': 361, 'P4': 361, 'P5': 361,"P100":361}

In [2]: import re

In [3]: patt =  re.compile("[^\d]")

In [4]: def cmp(x):
   ...:         return patt.search(x).group(), int(patt1.search(x).group())
   ...: print(sorted(d.items(), key=lambda x: (-x[1], cmp(x[0]))))
   ...: print(sorted(d.items(), key=lambda x: (-x[1], x[0])))
   ...: 
[('P3', 391), ('P4', 361), ('P5', 361), ('P6', 361), ('P100', 361), ('P200', 361), ('P1000', 361)]
[('P3', 391), ('P100', 361), ('P1000', 361), ('P200', 361), ('P4', 361), ('P5', 361), ('P6', 361)]

正则表达式的itertools替代方案,假设字符始终为alphas:

from itertools import  takewhile

def cmp(x):
    take = "".join(takewhile(str.isalpha, x))
    return take, int(x[len(take):])
print(sorted(d.items(), key=lambda x: (-x[1], (cmp(x[0])))))

如果它总是1个字母,那么是n个数字,它可以简化为:

sorted(d.items(), key=lambda x: (-x[1], (x[0][0], int(x[0][1:])))