簡體   English   中英

按字段名稱對命名元組列表進行排序的 Pythonic 方法

[英]Pythonic way to sorting list of namedtuples by field name

我想對命名元組列表進行排序,而不必記住字段名的索引。 我的解決方案似乎很尷尬,希望有人能有一個更優雅的解決方案。

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'))))

謝謝,尼克

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)]

按名稱排序列表

sorted(seq, key=attrgetter('name'))

按年齡排序列表

sorted(seq, key=attrgetter('age'))
sorted(seq, key=lambda x: x.name)
sorted(seq, key=lambda x: x.age)

我測試了這里給出的兩個替代方案以提高速度,因為@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))

結果:

attrgetter_test_name 44.26793992166096
attrgetter_test_age 31.98247099677627
lambda_test_name 47.97959511074551
lambda_test_age 35.69356267603864

使用 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))

結果:

attrgetter_test_both 92.80101586919373
lambda_test_both 96.85089983147456

Lambda 仍然表現不佳,但沒那么嚴重。 現在大約慢了 5%。

測試在 Python 3.6.0 上完成。

因為沒有人提到使用 itemgetter(),這里你如何使用 itemgetter()。

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(0)))

# sort list by age
print(sorted(seq, key=itemgetter(1)))

這對某些人來說可能有點太“神奇”了,但我偏向於:

# sort list by name
print(sorted(seq, key=Person.name.fget))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM