J'essaie de déterminer si une liste d'entiers est cohérente ou «à un étirement», ce qui signifie que la différence entre deux éléments voisins doit être exactement une et que les chiffres doivent augmenter monotone. Je trouvé une approche soignée où nous pouvons regrouper par le numéro de la liste moins la position de l'élément de la liste - Cette différence change lorsque les chiffres ne sont pas cohérents. Évidemment, il devrait y avoir exactement un groupe lorsque la séquence ne contient pas de lacunes ni de répétitions.
Test: p> Ça fonctionne bien, mais je constate personnellement que cette solution est Un peu trop convolué en vue de la simplicité du problème. Pouvez-vous trouver un moyen plus clair d'obtenir la même chose sans augmenter considérablement la longueur de code? P> à partir des réponses données ci-dessous, la solution p> EDIT: Résumé des réponses H1>
import itertools
import numpy as np
import timeit
setup = """
import numpy as np
def is_coherent_groupby(seq):
return len(list(g for _, g in itertools.groupby(enumerate(seq), lambda (i,e): i-e))) == 1
def is_coherent_npdiff(x):
return all(np.diff(x) == 1)
def is_coherent_zip(seq):
return all(x==y+1 for x, y in zip(seq[1:], seq))
def is_coherent_izip_longest(l):
return all(a==b for a, b in itertools.izip_longest(l, xrange(l[0], l[-1]+1)))
def is_coherent_all_xrange(l):
return all(l[i] + 1 == l[i+1] for i in xrange(len(l)-1))
def is_coherent_range(seq):
return seq == range(seq[0], seq[-1]+1)
small_list = range(10**3)
large_list = range(10**6)
larger_list = range(10**7)
very_large_list = range(10**8)
"""
fs = [
'is_coherent_groupby',
'is_coherent_npdiff',
'is_coherent_zip',
'is_coherent_izip_longest',
'is_coherent_all_xrange',
'is_coherent_range'
]
for n in fs:
print "Testing %s..." % n
t1 = timeit.timeit(
'%s(small_list)' % n,
setup,
number=40000
)
t2 = timeit.timeit(
'%s(large_list)' % n,
setup,
number=100
)
t3 = timeit.timeit(
'%s(larger_list)' % n,
setup,
number=10
)
t4 = timeit.timeit(
'%s(very_large_list)' % n,
setup,
number=1
)
print " small/large/larger/verylarge duration: %.2f s, %.2f s, %.2f s, %.2f s" % (t1, t2, t3, t4)
print " largest/smallest = %.2f" % (t4/t1)
6 Réponses :
Comment ou si elle est cohérente si elle est déjà triée p> Si vous utilisez Python 3, vous aurez besoin de Liste (plage (...)) code> p> p>
Ne pouviez-vous pas simplement faire list == Plage (liste [0], liste [-1] +1) code>? :)
Vous n'avez pas besoin de trier ou d'un min code> ou
max code>. La monotonicité est exigence! Voir:
>>> L1 == gamme (L1 [0], L1 [-1] +1) -> True code> - J'aime cette approche, nous devons maintenant penser à la performance :)
Ouais je ne sais pas ... cela dépend de la façon dont vous définissez cohérent ahh vous avez ajouté plus d'exemples dans une modification que je vois :) ...
Vous aurez besoin d'envelopper plage () code> dans
liste () code> pour python 3; peut-être la peine de mentionner cela.
@Joranbeasleasley: Je l'ai défini comme «ce qui signifie que la différence entre deux éléments voisins doit être exactement une et que les chiffres doivent augmenter monotone» dans la question.
Souhaitez-vous discuter de la performance de cette approche? Cela nécessite la création d'une liste potentiellement importante et de comparer deux listes potentiellement volumineuses. En outre, en ce qui concerne les exigences, vous pouvez ajouter en toute sécurité list == plage (liste [0], liste [-1] +1) code> à votre réponse! (EDIT: Maintenant, Carl l'a déjà fait ...)
La gamme (0.100000000) prend environ 5 secondes ... La comparaison a pris environ 1 seconde (sur mon système)
La plage list == (liste [0], liste [-1] +1) code> solution gagne, voir Modifier dans ma réponse pour des informations de synchronisation détaillées. Merci!
Je ne sais pas python mais je connais son fonctionnel afin que heres une petite fonction de boucle qui le fera si vous changez la syntaxe pour un python correct.
pseudo code strong> p> def is_coherent(seq):
for x in xrange(1, len(seq)-1):
if (seq[x+1]-seq[x] != 1) return false;
return true
def is_coherent(seq): return all(x==y+1 for x, y in zip(seq[1:], seq))
Retirez les crochets et vous transformez votre compréhension de la liste en une compréhension génératrice.
sauf si je néglige quelque chose dans vos exemples, cette solution plus simple est en réalité plus courte. Les résultats de certains tests de performance de base semblent indiquer que cette méthode est nettement plus rapide (je ' J'ai ajouté votre exemple comme is_coherent2 code>): p>
Fondamentalement la même chose que suggérée par @joranbeasley - Comment vous attendriez-vous à ce que cela fonctionne par rapport à la solution iTertools? Voulez-vous effectuer une analyse comparative?
Mis à jour avec des exemples code> TIMINIT CODE>.
Ce court circuits et ne crée pas de liste supplémentaire, ce qui permet de tester de très grandes listes.
def is_coherent(l): return all(l[i] + 1 == l[i+1] for i in xrange(len(l)-1))
Cela sera probablement plus rapide et plus efficace que mes solutions
Je reprends cela est beaucoup plus lent que ma méthode ... mais probablement une meilleure mémoire de mémoire, alors devrait toujours bien fonctionner pour de très grandes listes (comme plus de 10 millions de millions)
@Joranbeasleas: plus de mémoire efficace? Oui. Mais plus vite? Probablement pas parce que la création de la liste est ridiculement rapide, même pour des listes relativement volumineuses.
@Joranbeasleasley: également, comparer deux listes comme étant égales est mise en œuvre dans C.
Le izip_longest code> -Based une échelle une solution meilleure et intéressante (voir Modifier dans ma réponse)!
Si vous recherchez une solution numpue:
import numpy as np def is_coherent(x): return all(np.diff(x) == 1) is_coherent(np.array([1,2,3,4,5])) Out[39]: True is_coherent(np.array([1,2,3,4,8])) Out[40]: False