estoy trabajando a través de Allen Downey Cómo Pensar como un Informático, y he escrito lo que yo creo que es una solución funcionalmente correcta al ejercicio 10.10 . Pero me llevó algo más de 10 horas (!) Ejecutar, así que me pregunto si me falta algo de optimización realmente obvia y útil.Cómo optimizar el código Python (de ThinkPython, el ejercicio 10.10)
Aquí está el ejercicio:..
" 'enclavamiento' Dos palabras si tomar cartas alternando de cada uno forma una nueva palabra Por ejemplo, 'zapato' y el enclavamiento de 'frío' para formar 'educado' Escribir un programa que encuentra todos los pares de palabras que se entrelazan. Sugerencia: ¡No enumere todos los pares! "
(.. Para estos problemas lista de palabras, Downey ha suministrado un archivo con 113809 palabras Podemos suponer que estas palabras están en una lista, una palabra por elemento de la lista)
aquí está mi solución:
from bisect import bisect_left
def index(lst, target):
"""If target is in list, returns the index of target; otherwise returns None"""
i = bisect_left(lst, target)
if i != len(lst) and lst[i] == target:
return i
else:
return None
def interlock(str1, str2):
"Takes two strings of equal length and 'interlocks' them."
if len(str1) == len(str2):
lst1 = list(str1)
lst2 = list(str2)
result = []
for i in range(len(lst1)):
result.append(lst1[i])
result.append(lst2[i])
return ''.join(result)
else:
return None
def interlockings(word_lst):
"""Checks each pair of equal-length words to see if their interlocking is a word; prints each successful pair and the total number of successful pairs."""
total = 0
for i in range(1, 12): # 12 because max word length is 22
# to shorten the loops, get a sublist of words of equal length
sub_lst = filter(lambda(x): len(x) == i, word_lst)
for word1 in sub_lst[:-1]:
for word2 in sub_lst[sub_lst.index(word1)+1:]: # pair word1 only with words that come after word1
word1word2 = interlock(word1, word2) # interlock word1 with word2
word2word1 = interlock(word2, word1) # interlock word2 with word1
if index(lst, word1word2): # check to see if word1word2 is actually a word
total += 1
print "Word 1: %s, Word 2: %s, Interlock: %s" % (word1, word2, word1word2)
if index(lst, word2word1): # check to see if word2word1 is actually a word
total += 1
print "Word 2, %s, Word 1: %s, Interlock: %s" % (word2, word1, word2word1)
print "Total interlockings: ", total
Las declaraciones de impresión no son el problema; mi programa encontró solo 652 de esos pares. El problema son los bucles anidados, ¿verdad? Quiero decir, aunque estoy revisando listas que contienen solo palabras de la misma longitud, hay (por ejemplo) 21727 palabras de longitud 7, lo que significa que mi programa debe verificar más de 400 millones de "enclavamientos" para ver si ' re palabras reales --- y eso es solo para la longitud-7 palabras.
De nuevo, este código tardó 10 horas en ejecutarse (y no encontró pares con palabras de longitud 5 o superior, en caso de que tuviera curiosidad). ¿Hay una mejor manera de resolver este problema?
Gracias de antemano por cualquier idea. Soy consciente de que "la optimización prematura es la raíz de todo mal" --- y quizás ya he caído en esa trampa --- pero en general, aunque normalmente puedo escribir código que se ejecuta correctamente, a menudo me cuesta escribir código que funciona bien
La respuesta a continuación tiene mucho sentido, pero estoy interesado si trataste de perfilar este código para identificar qué es lo que realmente lo hace lento. Otras cosas útiles para tratar de acelerar son simplemente ejecutarlo a través de Psyco o PyPy. – Glenjamin
@Glenjamin: No he perfilado el código porque no sé cómo. ¿Puede ofrecer un enlace a alguna documentación que explique cómo hacer esto? ¡Gracias! –
http://docs.python.org/library/profile.html lo explica mucho mejor que yo :) Versión corta: 'python -m cProfile myscript.py' – Glenjamin