2011-11-03 19 views
6

que tienen una serie de listas que se ve así:¿Cuál es la mejor manera de ordenar la lista con parámetros de clasificación personalizados en Python?

li1 = ['a.1', 'b.9', 'c.8', 'd.1', 'e.2'] 
li2 = ['a.4', 'b.1', 'c.2', 'd.2', 'e.4'] 

¿Cómo puedo reordenar los elementos en cada lista, de modo que el primer elemento es 'b.something'? Para el ejemplo anterior:

li1 = ['b.9', 'a.1', 'c.8', 'd.1', 'e.2'] 
li2 = ['b.1', 'a.4', 'c.2', 'd.2', 'e.4'] 

Mantener el orden después del primer elemento no es importante. Gracias por la ayuda.

+0

No estoy seguro, pero esta pregunta puede ser de su interés: http://stackoverflow.com/questions/2436607/how-to-use-re-match-objects-in-a-list-comprehension –

+0

solo me preguntaba por qué todos usaban 's.startwith ('b')', en lugar de 's [0] == 'b''. ¿hay alguna ventaja de rendimiento? si no, quiero guardar el uso de la memoria a largo plazo de mi cerebro. – yosukesabai

+0

@yosukesabai: Solo una respuesta usa 's.startwith ('b')'. Los otros usan 's.startwith ('b.')' Como se solicitó en la pregunta. –

Respuesta

4

reorganizar los elementos en cada lista, de modo que el primer elemento es 'b.something'

El mantenimiento de la orden después de que el primer elemento no es importante.

Eso no está ordenando, entonces. Conceptualmente, solo intentas llevar ese elemento al frente.

En otras palabras, desea una lista que consta de ese elemento, seguido de todo lo que no es ese elemento. Cambiando esto un poco para el caso donde hay múltiples b.something s, y notando que no nos importa lo que ocurra, siempre y cuando el primer elemento sea un b.something, podemos reformular eso: una lista de cada elemento que cumple la condición ("comienza con b. "), seguido de cada elemento que no cumple la condición. (. Esto se llama a veces partición; véase, por ejemplo std::partition en C++)

En Python, esto es tan simple como la descripción de esas dos list-componentes con listas por comprensión y pegarlos juntos:

[x for x in li if x.startswith('b.')] + [x for x in li if not x.startswith('b.')] 

... O puede pretender que está clasificando, solo con un grupo de elementos que realmente solo tienen dos valores después de aplicarse el key, y aplicar el key apropiado, como en la respuesta de Ignacio Vasquez-Abrams.

+0

Eso es lo más cercano a la solicitud. No sé qué tan rápido podría ser para 'ordenar' de todos modos, ya que tiene que leer la lista dos veces con la misma función para el filtrado. –

+0

guau, esto es genial. por alguna razón, unirme a la lista de comprensión nunca se me ocurrió. Gracias. – drbunsen

+0

@ Joël leer la lista dos veces solo causa sobrecarga de factor constante. La ordenación es O (n lg n), ya que 'sort' necesita poder ordenar arbitrariamente y, por lo tanto, debe hacer algún tipo de ordenamiento basado en la comparación, mientras que cada paso de filtrado de comprensión de lista se ve trivialmente como O (n). –

3

Puede utilizar sorted, que acepta un argumento key, y devuelve una lista:

>>> li1 = ['a.1', 'b.2', 'c.8'] 
>>> def k(s): 
...  if s.startswith('b.'): 
...   return 1 
...  else: 
...   return 2 
... 
>>> sorted(li1, key=k) 
['b.2', 'a.1', 'c.8'] 

k deberán devolver algo que puede ser comparada entre los elementos iterables.

Nota: sort cambie la entrada in situ y no devuelve nada, cuando sorted devuelva la lista ordenada y no modifique su lista. Ambos funcionan de la misma manera.

5

La clasificación de Python es estable, por lo que mantendrá el orden después del primer elemento independientemente.

li1.sort(key=lambda x: not x.startswith('b.')) 
+1

Esto es muy ingenioso, pero me imagino que algunos argumentarían que "explícito es mejor que implícito" significa que no debería tratar booleanos como valores comparables ('Falso

Cuestiones relacionadas