¿Ordenar una lista por múltiples atributos?

Resuelto headache asked hace 14 años • 8 respuestas

Tengo una lista de listas:

[[12, 'tall', 'blue', 1],
[2, 'short', 'red', 9],
[4, 'tall', 'blue', 13]]

Si quisiera ordenar por un elemento, digamos el elemento alto/bajo, podría hacerlo a través de s = sorted(s, key = itemgetter(1)).

Si quisiera ordenar por alto /bajo y por color, podría hacerlo dos veces, una para cada elemento, pero ¿hay alguna manera más rápida?

headache avatar Nov 20 '10 22:11 headache
Aceptado

Una clave puede ser una función que devuelve una tupla:

s = sorted(s, key = lambda x: (x[1], x[2]))

O puedes lograr lo mismo usando itemgetter(que es más rápido y evita una llamada a una función de Python):

import operator
s = sorted(s, key = operator.itemgetter(1, 2))

Y observe que aquí puede usar sorten lugar de usar sortedy luego reasignar:

s.sort(key = operator.itemgetter(1, 2))
Mark Byers avatar Nov 20 '2010 15:11 Mark Byers

No estoy seguro de si este es el método más pitónico... Tenía una lista de tuplas que necesitaban ordenarse primero por valores enteros descendentes y segundo alfabéticamente. Esto requirió invertir la ordenación de números enteros pero no la ordenación alfabética. Aquí estaba mi solución: (sobre la marcha en un examen, por cierto, ni siquiera sabía que se podían "anidar" funciones ordenadas)

a = [('Al', 2),('Bill', 1),('Carol', 2), ('Abel', 3), ('Zeke', 2), ('Chris', 1)]  
b = sorted(sorted(a, key = lambda x : x[0]), key = lambda x : x[1], reverse = True)  
print(b)  
[('Abel', 3), ('Al', 2), ('Carol', 2), ('Zeke', 2), ('Bill', 1), ('Chris', 1)]
Clint Blatchford avatar Apr 22 '2016 01:04 Clint Blatchford

Varios años de retraso para la fiesta, pero quiero clasificar según 2 criterios y utilizar reverse=True. En caso de que alguien más quiera saber cómo, puede incluir sus criterios (funciones) entre paréntesis:

s = sorted(my_list, key=lambda i: ( criteria_1(i), criteria_2(i) ), reverse=True)
ron_g avatar May 21 '2019 14:05 ron_g

Parece que podrías usar a listen lugar de a tuple. Creo que esto se vuelve más importante cuando se obtienen atributos en lugar de 'índices mágicos' de una lista/tupla.

En mi caso quería ordenar por múltiples atributos de una clase, donde las claves entrantes eran cadenas. Necesitaba una clasificación diferente en diferentes lugares y quería una clasificación predeterminada común para la clase principal con la que interactuaban los clientes; solo tener que anular las 'claves de clasificación' cuando realmente 'lo necesitaba', pero también de una manera que pudiera almacenarlas como listas que la clase podría compartir

Primero definí un método auxiliar.

def attr_sort(self, attrs=['someAttributeString']:
  '''helper to sort by the attributes named by strings of attrs in order'''
  return lambda k: [ getattr(k, attr) for attr in attrs ]

entonces para usarlo

# would defined elsewhere but showing here for consiseness
self.SortListA = ['attrA', 'attrB']
self.SortListB = ['attrC', 'attrA']
records = .... #list of my objects to sort
records.sort(key=self.attr_sort(attrs=self.SortListA))
# perhaps later nearby or in another function
more_records = .... #another list
more_records.sort(key=self.attr_sort(attrs=self.SortListB))

Esto utilizará la función lambda generada para ordenar la lista object.attrAy luego object.attrBsuponiendo que objecttiene un captador correspondiente a los nombres de cadena proporcionados. Y el segundo caso se solucionaría para object.attrCentonces object.attrA.

Esto también le permite exponer potencialmente opciones de clasificación externas para que un consumidor las comparta por igual, una prueba unitaria, o que tal vez le digan cómo quieren que se realice la clasificación para alguna operación en su API con solo tener que darle una lista y no acoplándolos a su implementación de back-end.

UpAndAdam avatar Aug 15 '2017 15:08 UpAndAdam

convierta la lista de listas en una lista de tuplas y luego ordene la tupla por múltiples campos.

 data=[[12, 'tall', 'blue', 1],[2, 'short', 'red', 9],[4, 'tall', 'blue', 13]]

 data=[tuple(x) for x in data]
 result = sorted(data, key = lambda x: (x[1], x[2]))
 print(result)

producción:

 [(2, 'short', 'red', 9), (12, 'tall', 'blue', 1), (4, 'tall', 'blue', 13)]
Golden Lion avatar Jul 12 '2021 15:07 Golden Lion