Cómo sacar el máximo provecho de una línea 🧠

¿Qué hay con el conteo de ceros?

El instinto básico de la mayoría es escribir una list comprehension:
max([len(i) for i in s.split('1')])

Funcionará. Pero primero divides la cadena (creando una lista en memoria) y luego la recorres en un bucle para crear otra lista de enteros para dársela a max(). Doble gasto de memoria sin motivo.

Pero también se puede usar un generador:
max((len(chunk) for chunk in s.split('1')))

En cuanto a memoria, esto está bien: no se crea una lista intermedia de longitudes. Pero en velocidad, las expresiones generadoras dentro de funciones integradas en Python son más lentas debido a la sobrecarga de iteración y llamadas a funciones a nivel de bytecode.

Y esto es aún mejor:
max(map(len, s.split('1')))

Nos deshacemos del bucle de Python. map está implementado en C, es perezoso, funciona rápido y no consume memoria. La mayoría se queda contenta con esto.

Pero... tampoco es óptimo. Pregúntate: ¿por qué calculamos las longitudes de todos los fragmentos antes de encontrar el máximo?

Las cadenas en Python se comparan lexicográficamente, carácter por carácter. Por lo tanto, la cadena "000" siempre es mayor que "00". No necesitamos calcular las longitudes de las subcadenas para compararlas.

¡Así es mejor!
len(max(s.split('1')))


¿Por qué es esta la mejor solución? 🤔
1. La llamada s.split('1') devuelve inmediatamente una lista de cadenas.
2. max() consume esa lista y a nivel de C compara las cadenas directamente. Sin map, sin llamadas a len para cada elemento, sin llamadas a funciones en un bucle.
3. Tomamos len() exactamente una vez, de la cadena ganadora.

Menos movimientos del intérprete = código más rápido.

#algosobes