python sorting namedtuple field-names

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)