7
votes

Python: Découvrez si une liste d'entiers est cohérente

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> xxx pré>

Ç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>

EDIT: Résumé des réponses H1>

à partir des réponses données ci-dessous, la solution p>

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)


0 commentaires

6 Réponses :


5
votes

Comment xxx

ou si elle est cohérente si elle est déjà triée xxx

Si vous utilisez Python 3, vous aurez besoin de Liste (plage (...))


8 commentaires

Ne pouviez-vous pas simplement faire list == Plage (liste [0], liste [-1] +1) ? :)


Vous n'avez pas besoin de trier ou d'un min ou max . La monotonicité est exigence! Voir: >>> L1 == gamme (L1 [0], L1 [-1] +1) -> True - 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 () dans liste () 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) à 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) solution gagne, voir Modifier dans ma réponse pour des informations de synchronisation détaillées. Merci!



0
votes

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


0 commentaires

1
votes
def is_coherent(seq):
    return all(x==y+1 for x, y in zip(seq[1:], seq))

1 commentaires

Retirez les crochets et vous transformez votre compréhension de la liste en une compréhension génératrice.



2
votes

sauf si je néglige quelque chose dans vos exemples, cette solution plus simple est en réalité plus courte. XXX

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 ): xxx


2 commentaires

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 TIMINIT .



1
votes

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))


5 commentaires

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 -Based une échelle une solution meilleure et intéressante (voir Modifier dans ma réponse)!



2
votes

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


0 commentaires