【问题标题】:Python - sort method parameter takes same precedencePython - 排序方法参数具有相同的优先级
【发布时间】:2014-06-26 13:22:15
【问题描述】:

在我的程序中,我想按姓名对所有联系人进行排序,先是姓氏,然后是名字。

我有代码可以为我做到这一点但是它并没有完全按照我的意愿去做。

例如,如果我有一个按当前代码排序的名称列表,它将如下所示:

Luke
Riyaan
Amanda Benson

如您所见,代码仍然以None 作为排序值,我想要的是这样的:

Amanda Benson
Luke
Riyaan

所以基本上,如果姓氏返回None,那么我希望程序以与具有姓氏的对象相同的优先级来排序名字。

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

import operator

...

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

【问题讨论】:

  • 你的联系方式是什么?它们也是类实例吗?你在课堂上实现了比较魔术方法吗?
  • 它们是存储在列表中的类实例。我不知道比较魔术方法是什么/意思,所以可能不是。

标签: python operator-keyword


【解决方案1】:

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

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)

【讨论】:

    【解决方案2】:

    最好的方法是在你的(我猜的)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]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2012-09-29
      • 2022-01-16
      • 1970-01-01
      相关资源
      最近更新 更多