Python使用对象列表的min函数

44

如何使用min函数的key参数来比较一个对象列表的第一个属性?

示例:

class SpecialNumber:
    def __init__(self, i):
        self.number = i

li = [SpecialNumber(1), SpecialNumber(3), SpecialNumber(2)]
4个回答

65

http://docs.python.org/library/operator.html#operator.attrgetter


from operator import attrgetter
min_num = min(li,key=attrgetter('number'))

示例交互会话:

>>> li = [SpecialNumber(1), SpecialNumber(3), SpecialNumber(2)]
>>> [i.number for i in li]
[1, 3, 2]
>>> min_num = min(li,key=attrgetter('number'))
>>> print min_num.number
1

3
operator.attrgetter 函数比使用 lambda 函数更快吗? - Rick
3
@RicksupportsMonica 是的,它更快了。https://dev59.com/KHE85IYBdhLWcg3wl0nF - congusbongus

60

这是:

min(li, key=lambda x: x.number)

你需要一个函数,接受一个SpecialNumber并返回它的元素。


能否通过返回 SpecialNumber 类来避免返回数字元素? - Pwnna
2
默认情况下它会返回 SpecialNumber 对象。要获取最小元素,只需运行:min(li, key=lambda x: x.number).number - viraptor

16

我会通过覆盖 __cmp__ 来完成它。

class SpecialNumber:
    def __init__(self, i):
        self.number = i

    def __repr__(self):
        return '<SpecialNumber(%d)>' % self.number

    def __cmp__(self, other):
        return cmp(self.number, other.number)

li = [SpecialNumber(1), SpecialNumber(3), SpecialNumber(2)]
print min(li) # <SpecialNumber(1)>

5
注意,在Python 3.0中,__cmp__已经不再使用。因此,您可以在类上使用__lt__、__eq__和functools.total_ordering装饰器使其正常工作(或定义__lt__、__gt__、__le__、__ge__、__eq__、__ne__)。 - Michael Scott Asato Cuthbert
2
这些应该是双下划线——显然这是用于Markdown加粗的标记... - Michael Scott Asato Cuthbert

1

getattr版本更快

import random
from operator import attrgetter

class Test:
    def __init__(self):
        self.a = random.random()

t = [Test() for i in range(10000)]

%timeit min(t, key=lambda x: x.a)
1000 loops, best of 3: 790 µs per loop

%timeit min(t,key=attrgetter('a'))
1000 loops, best of 3: 582 µs per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接