Python | ¿Cuál es más rápido para inicializar listas?

Python es un lenguaje muy flexible en el que una sola tarea se puede realizar de varias maneras, por ejemplo, la inicialización de listas se puede realizar de muchas maneras. Sin embargo, existen diferencias sutiles en estos métodos aparentemente similares. Python, que es popular por su simplicidad y legibilidad, es igualmente infame por ser lento en comparación con C++ o Java. Se sabe especialmente que el bucle ‘for’ es lento, mientras que métodos como map() y filter() son más rápidos porque están escritos en C. Conocer la forma mejor y más rápida de inicializar listas puede darle una ligera ventaja en la competencia. programación.

Las siguientes son algunas de las formas de inicializar listas (creamos listas de tamaño 1000 e inicializamos con ceros) en Python.

Usando un bucle for y append()
Creamos una lista vacía y ejecutamos un bucle for n veces usando el método append() para agregar elementos a la lista.

arr = []
for i in range(1000):
    arr.append(0)

Usar un ciclo while con una variable de contador
Esto es similar al método anterior. Sin embargo, usamos while loop en su lugar.

arr = []
i = 0
while(i<1000):
    arr.append(0)

Uso de comprensiones de lista
Consiste en corchetes que contienen una expresión seguida de una cláusula for y luego seguida de una cláusula if opcional. La expresión puede ser cualquier tipo de objeto que queramos poner en la lista. Como estamos inicializando la lista con ceros, nuestra expresión será simplemente 0.

arr = [0 for i in range(1000)]

Usando el operador
* El operador * se puede usar como [objeto]*n donde n es el número de elementos en la array.

arr = [0]*1000

Veamos el tiempo empleado por cada uno de ellos. Calcularemos el tiempo promedio que toma cada uno de estos métodos para inicializar una array de 10000 elementos más de 500 veces.

# import time module to calculate times
import time
  
# initialize lists to save the times
forLoopTime = []
whileLoopTime = []
listComprehensionTime = []
starOperatorTime = []
  
# repeat the process for 500 times
# and calculate average of times taken.
for k in range(500): 
  
    # start time
    start = time.time()
    # declare empty list
    a = []
    # run a for loop for 10000 times
    for i in range(10000):
        a.append(0)
    # stop time
    stop = time.time()
    forLoopTime.append(stop-start)
  
    # start time
    start = time.time()
    # declare an empty list
    a = []
    i = 0
    # run a for loop 10000 times
    while(i<10000):
        a.append(0)
        i+= 1
    stop = time.time()
    whileLoopTime.append(stop-start)
  
    start = time.time()
    # list comprehension to initialize list
    a = [0 for i in range(10000)] 
    stop = time.time()
    listComprehensionTime.append(stop-start)
  
  
    start = time.time()
    # using the * operator
    a = [0]*10000 
    stop = time.time()
    starOperatorTime.append(stop-start)
  
  
  
print("Average time taken by for loop: " + str(sum(forLoopTime)/100))
print("Average time taken by while loop: " + str(sum(whileLoopTime)/100))
print("Average time taken by list comprehensions: " + str(sum(listComprehensionTime)/100))
print("Average time taken by * operator: " + str(sum(starOperatorTime)/100))    

Producción

Average time taken by for loop: 0.012432687282562256
Average time taken by while loop: 0.017907898426055908
Average time taken by list comprehensions: 0.0034629487991333007
Average time taken by * operator: 0.0001951146125793457

Nota: Los tiempos variarán según la plataforma donde se ejecute este código. Estos tiempos son solo para estudiar el rendimiento relativo de estos métodos de inicialización.

  • Como puede verse, los bucles for y while tardan casi el mismo tiempo que el bucle for, que tiene una ligera ventaja.
  • Las listas de comprensión funcionan mucho mejor que los bucles for y while, siendo el primero entre 3 y 5 veces más rápido. Otro ejemplo de esta diferencia se puede ver cuando intentamos crear una lista de números del 1 al 1000. Usar listas de comprensión es mucho mejor que usar append().
    a = [i for  i in range(1, 1001)]
  • Usar el operador * es mucho más rápido que los métodos restantes y esta es la forma en que debe inicializar las listas

Sin embargo, una desventaja de usar el operador * es al declarar arrays 2d. El uso de este operador crearía listas poco profundas, es decir, solo se crearía un objeto de lista y todos los índices se referirían a este objeto. Esto podría crear complicaciones no deseadas. Por lo tanto, usar listas por comprensión es una forma más segura de crear listas en 2D.


Using * operator would create shallow lists
arr = [[0]*no_of_cols]*no_of_rows

Using list comprehensions is better for 2d arrays
arr = [[0 for i in range(no_of_cols)] for j in range(no_of_rows)]

Publicación traducida automáticamente

Artículo escrito por Pranav Devarakonda y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *