Ok, mi primera respuesta ha sido bastante floja, así que pensé en probar algunas formas diferentes de hacer esto y reportar las diferencias. Aquí está mi código.
import sys
import itertools
def getFirstDup(c, toTest):
# Original idea using list slicing => 5.014 s
if toTest == '1':
for i in xrange(0, len(c)):
if c[i] in c[:i]:
return c[i]
# Using two sets => 4.305 s
elif toTest == '2':
s = set()
for i in c:
s2 = s.copy()
s.add(i)
if len(s) == len(s2):
return i
# Using dictionary LUT => 0.763 s
elif toTest == '3':
d = {}
for i in c:
if i in d:
return i
else:
d[i] = 1
# Using set operations => 0.772 s
elif toTest == '4':
s = set()
for i in c:
if i in s:
return i
else:
s.add(i)
# Sorting then walking => 5.130 s
elif toTest == '5':
c = sorted(c)
for i in xrange(1, len(c)):
if c[i] == c[i - 1]:
return c[i]
# Sorting then groupby-ing => 5.086 s
else:
c = sorted(c)
for k, g in itertools.groupby(c):
if len(list(g)) > 1:
return k
return None
c = list(xrange(0, 10000000))
c[5000] = 0
for i in xrange(0, 10):
print getFirstDup(c, sys.argv[1])
Básicamente, trato de esto de seis maneras diferentes, como se indica en el archivo fuente. He utilizado el comando Linux time
y recogieron los tiempos de ejecución en tiempo real, la ejecución de los comandos al igual que
time python ./test.py 1
con 1
ser que el algoritmo que quería probar. Cada algoritmo busca el primer duplicado en 10,000,000 de enteros y se ejecuta diez veces. Hay una duplicación en la lista, que está "en su mayoría ordenadas", aunque lo intenté revertir listas ordenadas y sin notar una diferencia proporcional entre los algoritmos.
Mi sugerencia original hizo mal en 5.014 s. Mi comprensión de la solución de icyrock.com también fue deficiente a las 4.305 s. Luego intenté usar un diccionario para crear una LUT, que dio el mejor tiempo de ejecución a 0.763 s. He intentado utilizar el operador in
en conjuntos, y obtuve 0,772 s, casi tan buenos como el diccionario LUT. Traté de ordenar y caminar la lista, que dio un tiempo lastimoso de 5.130 s. Finalmente, probé la sugerencia de John Machin de las itertools, que dio un tiempo de 5.086 s.
En resumen, un diccionario LUT parece ser el camino a seguir, con operaciones de conjuntos (que puede utilizar en su aplicación LUT) que es un cercano segundo lugar.
Actualización: Me trató la sugerencia de razpeitia, y aparte del hecho de que lo que necesita saber exactamente lo que copia de la llave que está buscando, el algoritmo real hizo el peor hasta el momento (66.366 s).
Actualización 2: Estoy seguro de que alguien va a decir que esta prueba es parcial porque la ubicación duplicado es cerca de un extremo de la lista. ¡Intenta ejecutar el código usando una ubicación diferente antes de la votación negativa e informa tus resultados!
¡Su método ES eficiente! =) Es el tiempo y el espacio 'O (N)' (lo mejor que puedes hacer es que 'x in myList' es' O (N) ', mira http://wiki.python.org/moin/TimeComplexity). Hay formas de mejorar la eficiencia de espacio para un golpe menor a la eficiencia de tiempo (por ejemplo, filtros de floración). La otra forma en que puede mejorar significativamente es regresar instantáneamente en ciertos tipos de listas, p. [0,1,1,2,3,4,5, ...].Esto supone un poco sobre la distribución de sus listas (por ejemplo, ¿se optimiza para este caso, o se duplica al final, o ambas cosas?), Pero puede ser una optimización que vale la pena ya que no afecta la velocidad asintótica. – ninjagecko