ordena la lista de Python con dos teclas pero solo una en orden inverso

Me preguntaba cuál sería una forma Pythonic de clasificar una lista de tuplas por dos claves, por lo que la clasificación con una (y solo una) estaría en orden inverso y la clasificación con la otra sería insensible a las mayúsculas. Más específicamente, tengo una lista que contiene tuplas como:

myList = [(ele1A, ele2A),(ele1B, ele2B),(ele1C, ele2C)] 

Puedo usar el siguiente código para clasificarlo con dos claves:

 sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1])) 

Para ordenar en orden inverso puedo usar

 sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1]), reverse = True) 

pero esto se ordenaría en orden inverso con dos teclas.

Cualquier consejo muy apreciado.

Se utilizarán dos claves cuando necesitamos ordenar una lista con dos restricciones, una en orden ascendente y otra en forma descendente en la misma lista o cualquiera
En tu ejemplo
sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1])) puede ordenar la lista completa solo en un orden
Puedes probar estos y ver qué está pasando

 sortedList = sorted(myList, key = lambda y: (y[0].lower(), -y[1])) sortedList = sorted(myList, key = lambda y: (-y[0].lower(), y[1])) sortedList = sorted(myList, key = lambda y: (-y[0].lower(), -y[1])) 

Espero que lo entiendas después de esto;)

A veces hay pocas alternativas más que usar una función de comparación. Hubo un argumento de cmp para sorted desde su introducción a 2.4, pero se eliminó de Python 3 en favor de la función de key más eficiente. En 3.2, se agregó functools a functools ; crea claves a partir de los objetos originales al envolverlos en un objeto cuya función de comparación se basa en la función cmp . (Puede ver una definición simple de cmp_to_key al final de Cómo ordenar)

En su caso, dado que la carcasa inferior es relativamente costosa, es posible que desee hacer una combinación:

 class case_insensitive_and_2nd_reversed: def __init__(self, obj, *args): self.first = obj[0].lower() self.second = obj[1] def __lt__(self, other): return self.first < other.first or self.first == other.first and other.second < self.second def __lt__(self, other): return self.first < other.first or self.first == other.first and other.second < self.second def __gt__(self, other): return self.first > other.first or self.first == other.first and other.second > self.second def __le__(self, other): return self.first < other.first or self.first == other.first and other.second <= self.second def __ge__(self, other): return self.first > other.first or self.first == other.first and other.second >= self.second def __eq__(self, other): return self.first == other.first and self.second == other.second def __ne__(self, other): return self.first != other.first and self.second != other.second sortedList = sorted(myList, key = case_insensitive_and_2nd_reversed) 

Método 1

Una solución simple, pero que no sea la más eficiente, es clasificar dos veces: la primera vez que se usa el segundo elemento, la segunda se usa el primer elemento:

 sortedList = sorted(sorted(myList, key=lambda (a,b):b, reverse=True), key=lambda(a,b):a) 

O descomponer:

 tempList = sorted(myList, key=lambda (a,b):b, reverse=True) sortedList = sorted(tempList, key=lambda(a,b):a)) 

Método 2

Si tus elementos son números, puedes engañar un poco:

 sorted(myList, key=lambda(a,b):(a,1.0/b)) 

Método 3

Otro enfoque es intercambiar los elementos al comparar los elementos:

 def compare_func(x, y): tup1 = (x[0], y[1]) tup2 = (x[1], y[0]) if tup1 == tup2: return 0 elif tup1 > tup2: return 1 else: return -1 sortedList = sorted(myList, cmp=compare_func) 

O, usando lambda para evitar la función de escritura:

 sortedList = sorted( myList, cmd=lambda (a1, b1), (a2, b2): 0 if (a1, b2) == (a2, b1) else 1 if (a1, b2) > (a2, b1) else -1 ) 

Recomiendo este enfoque, ya que es desordenado y la palabra clave cmd no está disponible en Python 3