Pythonic方法按字段名称排序namedtuples列表

Nic*_*ick 50 python sorting field-names namedtuple

我想排序一个命名元组列表,而不必记住fieldname的索引.我的解决方案似乎相当尴尬,并希望有人会有一个更优雅的解决方案.

from operator import itemgetter
from collections import namedtuple

Person = namedtuple('Person', 'name age score')
seq = [
    Person(name='nick', age=23, score=100),
    Person(name='bob', age=25, score=200),
]

# sort list by name
print(sorted(seq, key=itemgetter(Person._fields.index('name'))))
# sort list by age
print(sorted(seq, key=itemgetter(Person._fields.index('age'))))
Run Code Online (Sandbox Code Playgroud)

谢谢,尼克

jam*_*lak 72

from operator import attrgetter
from collections import namedtuple

Person = namedtuple('Person', 'name age score')
seq = [Person(name='nick', age=23, score=100),
       Person(name='bob', age=25, score=200)]
Run Code Online (Sandbox Code Playgroud)

按名称排序列表

sorted(seq, key=attrgetter('name'))
Run Code Online (Sandbox Code Playgroud)

按年龄排序列表

sorted(seq, key=attrgetter('age'))
Run Code Online (Sandbox Code Playgroud)


cly*_*ish 49

sorted(seq, key=lambda x: x.name)
sorted(seq, key=lambda x: x.age)
Run Code Online (Sandbox Code Playgroud)

  • 我认为这比使用`attrgetter`更优雅 (7认同)
  • @zenpoy记住`attrgetter`表现得更好,而'lambda'通常不被认为是优雅的 (3认同)
  • 我更喜欢attrgetter,但这只是味道.如果我要让字段动态排序,也是一个优点.然后我可以传递字符串. (2认同)
  • 和`sorted(seq, key=lambda x: [x.age, x.name])` 按多个属性排序 (2认同)

And*_*sen 9

我测试了这里给出的两个替代速度,因为@zenpoy关注性能.

测试脚本:

import random
from collections import namedtuple
from timeit import timeit
from operator import attrgetter

runs = 10000
size = 10000
random.seed = 42
Person = namedtuple('Person', 'name,age')
seq = [Person(str(random.randint(0, 10 ** 10)), random.randint(0, 100)) for _ in range(size)]

def attrgetter_test_name():
    return sorted(seq.copy(), key=attrgetter('name'))

def attrgetter_test_age():
    return sorted(seq.copy(), key=attrgetter('age'))

def lambda_test_name():
    return sorted(seq.copy(), key=lambda x: x.name)

def lambda_test_age():
    return sorted(seq.copy(), key=lambda x: x.age)

print('attrgetter_test_name', timeit(stmt=attrgetter_test_name, number=runs))
print('attrgetter_test_age', timeit(stmt=attrgetter_test_age, number=runs))
print('lambda_test_name', timeit(stmt=lambda_test_name, number=runs))
print('lambda_test_age', timeit(stmt=lambda_test_age, number=runs))
Run Code Online (Sandbox Code Playgroud)

结果:

attrgetter_test_name 44.26793992166096
attrgetter_test_age 31.98247099677627
lambda_test_name 47.97959511074551
lambda_test_age 35.69356267603864
Run Code Online (Sandbox Code Playgroud)

使用lambda确实比较慢.慢了10%.

编辑:

进一步测试显示使用多个属性排序时的结果.添加了以下两个具有相同设置的测试用例:

def attrgetter_test_both():
    return sorted(seq.copy(), key=attrgetter('age', 'name'))

def lambda_test_both():
    return sorted(seq.copy(), key=lambda x: (x.age, x.name))

print('attrgetter_test_both', timeit(stmt=attrgetter_test_both, number=runs))
print('lambda_test_both', timeit(stmt=lambda_test_both, number=runs))
Run Code Online (Sandbox Code Playgroud)

结果:

attrgetter_test_both 92.80101586919373
lambda_test_both 96.85089983147456
Run Code Online (Sandbox Code Playgroud)

Lambda仍然表现不佳,但不那么好.现在慢了约5%.

测试在Python 3.6.0上完成.

  • 感谢您提供多属性排序案例:) (2认同)