Python - Cómo ordenar la lista con sort() y sorted()

En esta guía, aprenda cómo ordenar una lista de cadenas, enteros y tuplas en Python con sort() y sorted(), ¡la diferencia entre los métodos y cómo se mantienen en un punto de referencia de rendimiento!

En esta breve guía, aprenda a ordenar una lista en Python usando las funciones integradas sort() y sorted().

  • sort() es un método de la clase list, y ordena la lista en el lugar, devolviendo Ninguno.
  • sorted() es un método integrado en el espacio de nombres de Python, y ordena la lista fuera de lugar, devolviendo una copia ordenada de la lista, sin afectar la original.

En términos generales, sort() es más eficiente en conjuntos de datos más grandes, mientras que sorted() es más conveniente, porque devuelve una copia de la lista y deja intacta la original.

{.icon aria-hidden=“true”}

Nota: Ambos métodos, de forma predeterminada, usan el operador lógico menor que (<) para la comparación de elementos y, por lo tanto, ordenan en orden ascendente. Puede anular la función de comparación predeterminada y, por extensión, tanto la lógica de comparación como el orden de clasificación.

En las secciones siguientes, veremos cómo ordenar listas de varios tipos de datos, incluidas funciones de comparación personalizadas, orden descendente y realizar una evaluación comparativa de rendimiento en los dos.

Ordenar lista con sort() y sorted()

Se llama a la función sort() en una lista que nos gustaría ordenar, y la ordena en el lugar, devolviendo Ninguno:

1
2
# my_list is sorted in-place - the original list is changed
my_list.sort()

Se ordena en orden ascendente de forma predeterminada. Para ordenar en orden descendente, puede proporcionar el argumento reverse=True a la función:

1
my_list.sort(reverse=True)

La función sorted() funciona de la misma manera que la función sort() - y también acepta los mismos argumentos. Sin embargo, sorted() crea una copia de la lista que proporcionamos, ordena la copia y la devuelve, dejando el original intacto:

1
2
# Sorts copy of `my_list` and returns it
sorted_list = sorted(my_list)

La forma en que se realizan las comparaciones depende del tipo de datos de los elementos de la lista. Las cadenas se comparan de manera diferente a los enteros, que a su vez se comparan de manera diferente a los objetos personalizados, por ejemplo.

Ordenar lista de cadenas

Las cadenas se ordenan lexicográficamente, en comparación con el operador >:

1
2
3
4
5
string_list = ['I', 'see', 'skies', 'of', 'blue', 'red', 'roses', 'too']

string_list.sort()
print(string_list)
# ['I', 'blue', 'of', 'red', 'roses', 'see', 'skies', 'too']

La misma lógica se aplica a la función sorted():

1
2
3
sorted_list = sorted(string_list)
print(sorted_list)
# ['I', 'blue', 'of', 'red', 'roses', 'see', 'skies', 'too']

I tiene un valor lexicográfico menor que blue, aunque b debería ir antes de i en el diccionario, porque las letras mayúsculas siempre tienen un valor lexicográfico menor que las letras minúsculas. Además de las letras mayúsculas, ¡el resto de las cadenas se ordenan en orden ascendente del diccionario!

Ordenar lista de enteros

Los números enteros son más sencillos en su comparación con el operador >:

1
2
3
4
5
int_list = [1, 7, 2, 3, 8, 5, 6]
int_list.sort()

print(int_list)
# [1, 2, 3, 5, 6, 7, 8]

O, con ordenado ():

1
2
3
sorted_list = sorted(int_list)
print(sorted_list)
# [1, 2, 3, 5, 6, 7, 8]

Ordenar lista de tuplas

Las tuplas se ordenan por clave, no por valor. Por ejemplo, supongamos que tiene una tabla de clasificación de lenguajes de programación preferidos, almacenados en una tupla de formato (idioma, rango); es posible que desee ordenarlos por orden de rango:

1
2
3
4
5
tuple_list = [('Java', 2), ('Python', 1), ('JavaScript', 3)]
tuple_list.sort()

print(tuple_list)
# [('Java', 2), ('JavaScript', 3), ('Python', 1)]

O, para ordenar una lista de tuplas con sorted():

1
2
3
sorted_tuples = sorted(tuple_list)
print(sorted_tuples)
# [('Java', 2), ('JavaScript', 3), ('Python', 1)]

Dado que las tuplas se ordenan por clave, esta lista de tuplas se ordena lexicográficamente, por las cadenas utilizadas como claves.

Ordenar lista de tuplas con clave personalizada

Para modificar el elemento según el orden de las tuplas, sin cambiar las tuplas en sí mismas, puede especificar cualquier elemento en una tupla en su lugar como argumento clave. Por lo general, es más fácil asignar la clave a otro elemento en la lista de tuplas, a través de una función lambda:

1
2
3
4
tuple_list = [('Java', 2), ('Python', 1), ('JavaScript', 3)]
tuple_list.sort(key=lambda x:x[1])
print(tuple_list)
# [('Python', 1), ('Java', 2), ('JavaScript', 3)]

O, con ordenado ():

1
2
3
sorted_tuples = sorted(tuple_list, key=lambda x:x[1])
print(sorted_tuples)
# [('Python', 1), ('Java', 2), ('JavaScript', 3)]

Aquí, hemos asignado la clave por la cual ordenar, al segundo elemento (la indexación se basa en 0) de la tupla, por lo tanto, ordenar por el segundo elemento (entero).

Si desea obtener más información sobre las funciones de Lambda, lea nuestra Guía de funciones de Lambda en Python.

{.icon aria-hidden=“true”}

Nota: La clave no corresponde al primer valor de la tupla, que a menudo se denomina "clave" como en un par "clave-valor". La clave se refiere a la clave mediante la cual el método sort() ordena los elementos.

Esto es válido para cualquier número de elementos de tupla:

1
2
3
4
5
tuple_list = [('Java', 2, 'General purpose'), ('Python', 1, 'General purpose'), ('JavaScript', 3, 'Web-oriented')]
tuple_list.sort(key=lambda x:x[1])

print(tuple_list)
# [('Python', 1, 'General purpose'), ('Java', 2, 'General purpose'), ('JavaScript', 3, 'Web-oriented')]

O, con ordenado ():

1
2
3
sorted_tuples = sorted(tuple_list, key=lambda x:x[1])
print(sorted_tuples)
# [('Python', 1, 'General purpose'), ('Java', 2, 'General purpose'), ('JavaScript', 3, 'Web-oriented')]

Ordenar lista con comparador personalizado

En última instancia, es posible que desee proporcionar un comparador personalizado al argumento clave de sort() o sorted(). Un comparador es simplemente una función que devuelve un tipo de retorno comparable. Por ejemplo, puede ordenar por longitud, pasando la función len():

1
2
3
4
5
string_list = ['I', 'see', 'skies', 'of', 'blue', 'red', 'roses', 'too']
string_list.sort(key=len)

print(string_list)
# ['I', 'of', 'see', 'red', 'too', 'blue', 'skies', 'roses']

O, con ordenado ():

1
2
3
sorted_list = sorted(string_list, key=len)
print(sorted_list)
# ['I', 'of', 'see', 'red', 'too', 'blue', 'skies', 'roses']

De manera similar, puede ordenar por cualquier función personalizada:

1
2
3
4
5
6
7
8
def custom_comparator(element):
    return element[-1]

string_list = ['I', 'see', 'skies', 'of', 'blue', 'red', 'roses', 'too']
string_list.sort(key=custom_comparator)

print(string_list)
# ['I', 'red', 'see', 'blue', 'of', 'too', 'skies', 'roses']

O, con ordenado ():

1
2
3
4
sorted_list = sorted(string_list, key=custom_comparator)

print(sorted_list)
# ['I', 'red', 'see', 'blue', 'of', 'too', 'skies', 'roses']

Aquí, simplemente hemos devolvió el último carácter de una cadena, a través de la notación de corte, y ordenados por ese carácter devuelto. Si presta atención al último carácter de cada palabra (excluyendo la letra mayúscula), se ordenan en orden lexicográfico.

Benchmarking sort() frente a sorted()

Como se indicó anteriormente, sorted() es un poco menos eficiente que sort(), principalmente porque crea una copia y ordena esa copia, en lugar de cambiar la colección original. Sin embargo, ¿cuánto es "ligeramente menos" eficiente?

Esto depende de varios factores, como su hardware y las características específicas de ese hardware, pero puede ejecutar una prueba muy simple para verificar cuál funciona mejor para usted, en función de múltiples tamaños de entrada.

Ordenemos listas de 10, 100 y 1000 elementos respectivamente, y cronometremos los tiempos de ejecución de estas funciones usando timeit. Para asegurarnos de que la prueba sea justa, queremos asegurarnos de que:

  • Las listas de elementos se generan antes de llamar a timeit(), por lo que la lógica de generación no tiene en cuenta el tiempo de referencia
  • Los métodos se ejecutan exactamente en la misma entrada

Dado que sort() cambia las listas en el lugar, ejecutaremos sorted() primero, y luego compararemos cuánto tiempo le toma a sort() hacer esas mismas listas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import timeit
import random

def generate_random_strings(num):
    result = []
    for i in range(num):
        s = ''.join(random.choice([chr(i) for i in range(ord('a'),ord('z'))]) for _ in range(5))
        result.append(s)
    return result

ten = generate_random_strings(10)
hundred = generate_random_strings(100)
thousand = generate_random_strings(1000)

# For eval() statements where input is translated to list names
mapping = {
    10:'ten',
    100:'hundred',
    1000:'thousand'
}

# Based on input, evaluate the expression to sort adequate list
def run_sort(num):
    eval(f'{mapping[num]}.sort()')

# Based on input, evaluate the expression to sort adequate list
def run_sorted(num):
    eval(f'sorted({mapping[num]})')

for index, num_samples in enumerate([10, 100, 1000]):
    result = timeit.timeit(f"run_sorted({num_samples})", number=100000, globals=globals())
    print(f'sorted() on {num_samples} took {result} seconds')

print('____________________________________________________')    
  
for index, num_samples in enumerate([10, 100, 1000]):
    result = timeit.timeit(f"run_sort({num_samples})", number=100000, globals=globals())
    print(f'sort() on {num_samples} took {result} seconds')

Este fragmento de código compara el tiempo que lleva ejecutar 100k iteraciones de cada uno de los métodos run_sort() y run_sorted(), en las mismas listas de 10, 100, 1000 y 1000000 elementos producidos por generate_random_strings( ) método, y da como resultado:

1
2
3
4
5
6
7
sorted() on 10 took 0.5450385000003735 seconds
sorted() on 100 took 0.9972869999996874 seconds
sorted() on 1000 took 10.934083999999984 seconds
____________________________________________________
sort() on 10 took 0.4839348999998947 seconds
sort() on 100 took 0.5398832000000766 seconds
sort() on 1000 took 1.3094285000001946 seconds

Para 10 elementos, el tiempo es prácticamente el mismo - ~0.5s. Sin embargo, tan pronto como con 100 elementos, sort() toma la mitad del tiempo para ordenar la misma lista. Finalmente, con 1000 elementos, sorted() toma casi diez ​​veces más tiempo de cálculo que sort().

Cuanto más grande sea el conjunto de datos con el que está trabajando, más beneficios obtendrá usando sort() en lugar de `sorted(), si no necesita un fuera de lugar clasificar.

Conclusión

En esta breve guía, hemos echado un vistazo a cómo ordenar una lista en Python con la ayuda de sort() y sorted().

Luego hemos explorado la clasificación en orden descendente, en lugar de ascendente, así como la configuración de una “clave” de clasificación diferente, incluida la escritura de un método de clasificación personalizado.

Finalmente, hemos evaluado los dos métodos y explorado cómo funcionan con un tamaño de entrada creciente.

Licensed under CC BY-NC-SA 4.0