python - Manera pitonica de clasificar la lista de miniaturas nombradas por nombre de campo
sorting namedtuple (4)
Quiero ordenar una lista de tuplas nombradas sin tener que recordar el índice del nombre de campo. Mi solución parece bastante incómoda y esperaba que alguien tuviera una solución más elegante.
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''))))
Gracias, Nick
Probé las dos alternativas dadas aquí para la velocidad, ya que @zenpoy estaba preocupado por el rendimiento.
Guión de prueba:
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))
Resultados:
attrgetter_test_name 44.26793992166096
attrgetter_test_age 31.98247099677627
lambda_test_name 47.97959511074551
lambda_test_age 35.69356267603864
Usar lambda fue de hecho más lento. Hasta 10% más lento.
EDITAR :
Pruebas adicionales muestran los resultados cuando se ordenan usando atributos múltiples. Se agregaron los dos casos de prueba siguientes con la misma configuración:
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))
Resultados:
attrgetter_test_both 92.80101586919373
lambda_test_both 96.85089983147456
Lambda aún no funciona bien, pero no tanto. Ahora aproximadamente un 5% más lento.
La prueba se realiza en Python 3.6.0.
ya que nadie mencionó usar itemgetter (), aquí cómo lo haces usando 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)))
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)]
Ordenar lista por nombre
sorted(seq, key=attrgetter(''name''))
Ordenar lista por edad
sorted(seq, key=attrgetter(''age''))
sorted(seq, key=lambda x: x.name)
sorted(seq, key=lambda x: x.age)