Ordenar una lista de Python por dos campos [duplicado]
Tengo la siguiente lista creada a partir de un csv ordenado
list1 = sorted(csv1, key=operator.itemgetter(1))
De hecho, me gustaría ordenar la lista según dos criterios: primero por el valor del campo 1 y luego por el valor del campo 2. ¿Cómo hago esto?
No es necesario importar nada cuando se utilizan funciones lambda.
Lo siguiente se clasifica list
por el primer elemento y luego por el segundo elemento. También puedes ordenar por un campo ascendente y otro descendente por ejemplo:
sorted_list = sorted(list, key=lambda x: (x[0], -x[1]))
como esto:
import operator
list1 = sorted(csv1, key=operator.itemgetter(1, 2))
Python tiene una clasificación estable, por lo que, siempre que el rendimiento no sea un problema, la forma más sencilla es ordenarlo por el campo 2 y luego ordenarlo nuevamente por el campo 1.
Eso le dará el resultado que desea, el único inconveniente es que si es una lista grande (o si desea ordenarla con frecuencia), llamar a ordenar dos veces podría ser una sobrecarga inaceptable.
list1 = sorted(csv1, key=operator.itemgetter(2))
list1 = sorted(list1, key=operator.itemgetter(1))
Hacerlo de esta manera también facilita el manejo de la situación en la que desea que algunas de las columnas se ordenen de manera inversa, simplemente incluya el parámetro 'reverse=True' cuando sea necesario.
De lo contrario, puede pasar varios parámetros a itemgetter o crear manualmente una tupla. Probablemente será más rápido, pero tiene el problema de que no se generaliza bien si algunas de las columnas quieren ordenarse de forma inversa (las columnas numéricas aún se pueden invertir negándolas, pero eso impide que la ordenación sea estable).
Entonces, si no necesita ninguna columna ordenada de manera inversa, busque múltiples argumentos para itemgetter, si es posible, y las columnas no son numéricas o si desea mantener la clasificación estable, opte por múltiples clasificaciones consecutivas.
Editar: Para los comentaristas que tienen problemas para entender cómo esto responde a la pregunta original, aquí hay un ejemplo que muestra exactamente cómo la naturaleza estable de la clasificación garantiza que podamos realizar clasificaciones separadas en cada clave y terminar con datos ordenados según múltiples criterios:
DATA = [
('Jones', 'Jane', 58),
('Smith', 'Anne', 30),
('Jones', 'Fred', 30),
('Smith', 'John', 60),
('Smith', 'Fred', 30),
('Jones', 'Anne', 30),
('Smith', 'Jane', 58),
('Smith', 'Twin2', 3),
('Jones', 'John', 60),
('Smith', 'Twin1', 3),
('Jones', 'Twin1', 3),
('Jones', 'Twin2', 3)
]
# Sort by Surname, Age DESCENDING, Firstname
print("Initial data in random order")
for d in DATA:
print("{:10s} {:10s} {}".format(*d))
print('''
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred''')
DATA.sort(key=lambda row: row[1])
for d in DATA:
print("{:10s} {:10s} {}".format(*d))
print('''
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.''')
DATA.sort(key=lambda row: row[2], reverse=True)
for d in DATA:
print("{:10s} {:10s} {}".format(*d))
print('''
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
''')
DATA.sort(key=lambda row: row[0])
for d in DATA:
print("{:10s} {:10s} {}".format(*d))
Este es un ejemplo ejecutable, pero para evitar que las personas lo ejecuten, el resultado es:
Initial data in random order
Jones Jane 58
Smith Anne 30
Jones Fred 30
Smith John 60
Smith Fred 30
Jones Anne 30
Smith Jane 58
Smith Twin2 3
Jones John 60
Smith Twin1 3
Jones Twin1 3
Jones Twin2 3
First we sort by first name, after this pass all
Twin1 come before Twin2 and Anne comes before Fred
Smith Anne 30
Jones Anne 30
Jones Fred 30
Smith Fred 30
Jones Jane 58
Smith Jane 58
Smith John 60
Jones John 60
Smith Twin1 3
Jones Twin1 3
Smith Twin2 3
Jones Twin2 3
Second pass: sort by age in descending order.
Note that after this pass rows are sorted by age but
Twin1/Twin2 and Anne/Fred pairs are still in correct
firstname order.
Smith John 60
Jones John 60
Jones Jane 58
Smith Jane 58
Smith Anne 30
Jones Anne 30
Jones Fred 30
Smith Fred 30
Smith Twin1 3
Jones Twin1 3
Smith Twin2 3
Jones Twin2 3
Final pass sorts the Jones from the Smiths.
Within each family members are sorted by age but equal
age members are sorted by first name.
Jones John 60
Jones Jane 58
Jones Anne 30
Jones Fred 30
Jones Twin1 3
Jones Twin2 3
Smith John 60
Smith Jane 58
Smith Anne 30
Smith Fred 30
Smith Twin1 3
Smith Twin2 3
Observe en particular cómo en el segundo paso el reverse=True
parámetro mantiene los nombres en orden, mientras que simplemente ordenar y luego invertir la lista perdería el orden deseado para la tercera clave de clasificación.