排序元组时忽略不可排序的数据类型

时间:2014-03-11 05:48:24

标签: python list sorting

我从一本书中自学Python,而且我一直在进行编程练习。练习的目的是创建一个对象列表,然后根据一些对象属性对这些对象进行排序。

我的教科书的作者说,在排序过程中使用键为每个比较调用类方法可以减慢大数据集的排序时间,并通过为每个对象调用类方法一次构建“装饰”列表您构建列表可以使后续排序更有效。编程问题规定,我应该创建一系列元组,而不是键,其中元组元素0是对象属性的文字值,而元组元素1是对象本身。在我有我的装饰列表后,我可以使用内置的列表排序方法(例如“sorted()”或“.sort()”等)将它们整理好。

当两个对象具有相同的排序属性值时,我收到错误。此示例代码将重现错误:

class Shrubber:
    def __init__(self, age):
        self.name = 'Roger'
        self.age = age

    def getAge(self):
        return self.age

def main():
    rogerAges = [30, 21, 21, 25]
    rogers = []
    for rAge in rogerAges:
        newShr = Shrubber(rAge)
        rogers.append((newShr.getAge(), newShr))
    rogers.sort()
    print(rogers)

main()

我希望程序打印出类似这样的内容:

[(21, <__main__.Shrubber object at XxXEX>), (21, <__main__.Shrubber object at YxYEY>), (25, <__main__.Shrubber object at ZxZEZ>), (30, <__main__.Shrubber object at QxQEQ>)]

...相反,它给了我一个TypeError:

TypeError: unorderable types: Shrubber() < Shrubber()

我确定我收到了错误,因为在Python遇到两个元组元素0的两个相同值之后,它会查找元素1并找到一个无法解析的数据类型(一个对象)。然而,两个灌木丛不能同年龄的限制使我觉得我错过了什么。

我的问题:我可以通过元组元素0稳定地对元组列表进行排序并忽略我的无法排序的元组元素1吗?

2 个答案:

答案 0 :(得分:1)

我不知道如何让它忽略这些情况下的第二个元素。另一种方法是向对象的类添加一个方法,该方法将返回所需的信息。这样做将避免需要传递sort() key=函数。这是我的意思的一个例子:

class Shrubber:
    def __init__(self, age):
        self.name = 'Roger'
        self.age = age

    def getAge(self):
        return self.age

    def __lt__(self, other):  # added comparison method
        return self.age < other.age

def main():
    rogerAges = [30, 21, 21, 25]
    rogers = []
    for rAge in rogerAges:
        newShr = Shrubber(rAge)
        rogers.append((newShr.getAge(), newShr))
    rogers.sort()
    print(rogers)

if __name__ == '__main__':
    main()

输出(为便于阅读而包装):

[(21, <__main__.Shrubber object at 0x00C1D830>),
 (21, <__main__.Shrubber object at 0x00C1D9D0>),
 (25, <__main__.Shrubber object at 0x00C1DA30>),
 (30, <__main__.Shrubber object at 0x00C1D9F0>)]

答案 1 :(得分:1)

如果确保比较永远不会通过Shrubber对象,则不必实现__lt__函数。一种方法是在该元组中插入另一个整数:

def main():
    rogerAges = [30, 21, 21, 25]
    rogers = list()
    for i, rAge in enumerate(rogerAges):
        newShr = Shrubber(rAge)
        rogers.append((newShr.getAge(), i, newShr))
    rogers.sort()
    print(rogers)

但是,从所有观点来看都是错误的,你应该使用key=函数。这很难阅读,根据我的测量,它大约慢四倍。尽管如此,使用__lt__(或已弃用的cmp=)的情况更糟,大约慢两倍。

作为最后一点,以这种方式附加到列表不是Pythonic方式。你可以这样做:

def main():
    rogerAges = [30, 21, 21, 25]
    rogers = [(rAge, i, Shrubber(rAge)) for (i, rAge) in enumerate(rogerAges)]
    rogers.sort()
    print(rogers)