Podría sumrse más rápido en las listas.

Esto es de alguna manera un seguimiento a esta pregunta.

Entonces, primero notará que no puede realizar una sum en una lista de cadenas para concatenarlas, Python le dice que use str.join en str.join lugar, y ese es un buen consejo, ya que no importa cómo use + en las cadenas, el rendimiento es malo. .

La restricción “no puede usar la sum ” no se aplica a la list , y sin embargo, itertools.chain.from_iterable es la forma preferida de realizar dicho aplanamiento de la lista.

Pero la sum(x,[]) cuando x es una lista de listas es definitivamente mala.

¿Pero debería seguir siendo así?

Comparé 3 enfoques

 import time import itertools a = [list(range(1,1000)) for _ in range(1000)] start=time.time() sum(a,[]) print(time.time()-start) start=time.time() list(itertools.chain.from_iterable(a)) print(time.time()-start) start=time.time() z=[] for s in a: z += s print(time.time()-start) 

resultados:

  • sum() en la lista de listas: 10.46647310256958. Está bien, lo sabíamos.
  • itertools.chain : 0.07705187797546387
  • sum acumulada personalizada con adición en el lugar: 0.057044029235839844 (puede ser más rápido que itertools.chain como ve)

Entonces, la sum está muy por detrás porque realiza el result = result + b lugar del result += b

Así que ahora mi pregunta:

¿Por qué la sum no puede usar este enfoque acumulativo cuando está disponible?

(Eso sería transparente para las aplicaciones ya existentes y haría posible el uso de la sum integrada para aplanar las listas de manera eficiente)

Related of "Podría sumrse más rápido en las listas."

Podríamos tratar de hacer que sum () sea más inteligente, pero Alex Martelli y Guido van Rossum querían mantenerlo centrado en las sums aritméticas.

FWIW, debería obtener un rendimiento razonable con este simple código:

 result = [] for seq in mylists: result += seq 

Para su otra pregunta, “¿por qué no se puede usar este enfoque acumulativo cuando está disponible?”, Vea este comentario para builtin_sum () en Python / bltinmodule.c:

  /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. */ 
 /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. */ temp = PyNumber_Add(result, item); 

Tomado del código fuente incorporado de Python https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L2146 Línea: 2342

FWIW, podemos engañar al intérprete para que nos permita usar la sum en las cadenas al pasar una instancia de clase personalizada apropiada como el start de sum a sum .

 class Q(object): def __init__(self, data=''): self.data = str(data) def __str__(self): return self.data def __add__(self, other): return Q(self.data + str(other)) print(sum(['abc', 'def', 'ghi'], Q())) 

salida

 abcdefghi 

Por supuesto, esto es una cosa bastante tonta de hacer. 🙂