Python - 排序方法参数具有相同的优先级

时间:2014-06-26 13:22:16

标签: python operator-keyword

在我的程序中,我想先按名字,姓氏,名字命名所有联系人。

我已经获得了代码,它为我做了但是它并没有完全符合我的要求。

例如,如果我有一个按照当前代码的顺序排列的名称列表,它将是这样的:

Luke
Riyaan
Amanda Benson

正如您所看到的,代码仍然需要None作为值进行排序,我想要的是:

Amanda Benson
Luke
Riyaan

所以基本上,如果姓氏返回None,那么我希望程序按照具有姓氏的对象的优先顺序排序第一个名称。

这是我目前用来对名称进行排序的代码:

import operator

...

addressBook = AddressBook()
addressBook.contactsList
addressBook.contactsList.sort(key = operator.attrgetter("lastName", "firstName"))

2 个答案:

答案 0 :(得分:3)

您需要一个自定义排序功能,然后在缺少姓氏时,将您的名字作为元组中的第一个值返回:

def name_sort(contact):
    if contact.lastName:
        return contact.lastName, contact.firstName
    return contact.firstName, ''

addressBook.contactsList.sort(key=name_sort)

可以使用lambda和条件表达式将其纳入sort()调用:

addressBook.contactsList.sort(key=lambda c: (c.lastName, c.firstName) if c.lastName else (c.firstName, ''))

我在这里为这两种情况生成一个2值元组,但是对于无名字的情况的单元素元组也应该足够了。

如果这是您感兴趣的唯一排序顺序,您可能需要查看提供rich comparison functions,以便您可以在没有密钥的情况下对对象进行排序;然后比较对象本身并提供排序顺序。

您不必实施所有丰富的比较方法;你需要的只是一个,加上__eq__(相等测试)和@functools.total_ordering() class decorator

from functools import total_ordering

@total_ordering
class Contact(object):
    # ...

    def __eq__(self, other):
        if self.lastName != other.lastName:
            return False
        return self.firstName == other.firstName

    def __lt__(self, other):
        if not self.lastName:
            if not other.lastName:
                return self.firstName < other.firstName
            return self.firstName < other.lastName
        return (self.lastName, self.firstName) < (other.lastName, other.firstName)

答案 1 :(得分:0)

执行此操作的最佳方法是在您的(我猜)Contact课程中实施the rich comparison magic methods

class Contact(object):

    def __init__(self, first_name, last_name=""):
        self.first_name = first_name
        self.last_name = last_name

    def __repr__(self): # to make the demo clearer!
        if not self.last_name:
            return str(self.first_name)
        return "{0.first_name} {0.last_name}".format(self)

    def __eq__(self, other):
        return (self.first_name == other.first_name and 
                self.last_name == other.last_name)

    def __lt__(self, other):
        if self.last_name and other.last_name:
            if self.last_name == other.last_name:
                return self.first_name < other.first_name
            return self.last_name < other.last_name
        else:
            if other.last_name:
                return self.first_name < other.last_name
            return self.first_name < other.first_name

现在您只需使用sortedlist.sort不带参数:

>>> contacts_list = [Contact("Luke"), Contact("Riyaan"), Contact("Amanda", "Benson")]
>>> sorted(contacts_list)
[Amanda Benson, Luke, Riyaan]