¿Cómo ordenar una lista según otra lista?

Hay una lista:

a = [("ax", 1), ("ec", 3), ("bk", 5)] 

otra lista:

 b = ["ec", "ax", "bk"] 

Quiero ordenar a acuerdo con b :

 sort_it(a, b) a = [("ec", 3), ("ax", 1), ("bk", 5)] 

¿Como hacer esto?

Related of "¿Cómo ordenar una lista según otra lista?"

 a.sort(key=lambda x: b.index(x[0])) 

Esto clasifica a in situ usando el índice en b del primer elemento de cada tupla de a como los valores que ordena.

Otra forma de escribir, posiblemente más limpia, sería:

 a.sort(key=lambda (x,y): b.index(x)) 

Si tuviera una gran cantidad de elementos, podría ser más eficiente hacer las cosas de manera un poco diferente, ya que .index() puede ser una operación costosa en una lista larga, y en realidad no necesita hacer una clasificación completa ya que ya saber el orden:

 mapping = dict(a) a[:] = [(x,mapping[x]) for x in b] 

Tenga en cuenta que esto solo funcionará para una lista de 2-tuplas. Si quieres que funcione para tuplas de longitud arbitraria, deberías modificarlo ligeramente:

 mapping = dict((x[0], x[1:]) for x in a) a[:] = [(x,) + mapping[x] for x in b] 

Otra posibilidad es ordenar a , ordenar los índices de b según b y luego ordenar a según los índices

 a.sort(key=lambda x: x[0]) ind = [i[0] for i in sorted(enumerate(b),key=lambda x: x[1])] a = [i[0] for i in sorted(zip(a,ind),key=lambda x: x[1])] 

ya que cada clasificación toma n * log (n) esto aún es escalable para listas más grandes

La clasificación tradicional puede no ser necesaria.

 [tup for lbl in b for tup in a if tup[0] == lbl] # [('ec', 3), ('ax', 1), ('bk', 5)] 

En realidad, hay una forma de hacerlo en tiempo O (n) lineal, porque esto no es realmente una operación de clasificación. La existencia de la lista b significa que la clasificación ya está hecha; todo lo que realmente necesitamos hacer es reorganizar los elementos de a para que estén en el mismo orden. Esto se puede hacer de manera eficiente gracias a los diccionarios.

 from collections import defaultdict def sorted_by(seq_to_sort, desired_order, key=None): if key is None: key = lambda x: x # group the elements by their key grouped_items = defaultdict(list) for item in seq_to_sort: k = key(item) grouped_items[k].append(item) # flatten the dict of groups to a list return [item for key in desired_order for item in grouped_items[key]] 

Uso:

 a = [("ax", 1), ("ec", 3), ("bk", 5)] b = ["ec", "ax", "bk"] result = sorted_by(a, b, lambda tup: tup[0]) print(result) # output: [("ec", 3), ("ax", 1), ("bk", 5)] 

Notas:

  • Este es un tipo estable; Si dos elementos de la lista tienen la misma clave, se conservará su orden. Ejemplo:

     >>> sorted_by([1, 2, 3], [5], key=lambda x: 5) [1, 2, 3] 
  • Si alguno de los elementos de la lista se asigna a claves que no existen en desired_order , esos elementos se descartan silenciosamente. Por ejemplo:

     >>> sorted_by([1, 2, 3], [1, 2, 3], key=lambda x: 5) [] 

Ver también:

  • defaultdict