J'aimerais identifier des groupes de nombres continus dans une liste, de sorte que:
myfunc([2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 20])
Retour:
[(2,5), (12,17), 20]
Et je me demandais quelle était la meilleure façon de le faire (en particulier s'il y a quelque chose d'incorporé dans Python).
Edit: Notez que j'ai initialement oublié de mentionner que les nombres individuels doivent être renvoyés sous forme de nombres individuels, pas de plages.
python
list
range
continuous
Mikemaccana
la source
la source
Réponses:
more_itertools.consecutive_groups
a été ajouté dans la version 4.0.Démo
Code
En appliquant cet outil, nous créons une fonction de générateur qui trouve des plages de nombres consécutifs.
L' implémentation source émule une recette classique (comme démontré par @Nadia Alramli).
Remarque:
more_itertools
est un package tiers installable viapip install more_itertools
.la source
EDIT 2: Pour répondre à la nouvelle exigence du PO
Production:
Vous pouvez remplacer xrange par range ou toute autre classe personnalisée.
Les documents Python ont une recette très soignée pour cela:
Production:
Si vous souhaitez obtenir exactement la même sortie, vous pouvez le faire:
production:
EDIT: L'exemple est déjà expliqué dans la documentation mais je devrais peut-être l'expliquer davantage:
Si les données étaient:
[2, 3, 4, 5, 12, 13, 14, 15, 16, 17]
Thengroupby(enumerate(data), lambda (i,x):i-x)
équivaut à ce qui suit:La fonction lambda soustrait l'index de l'élément de la valeur de l'élément. Ainsi, lorsque vous appliquez le lambda sur chaque élément. Vous obtiendrez les clés suivantes pour groupby:
groupby regroupe les éléments par valeur de clé égale, de sorte que les 4 premiers éléments seront regroupés et ainsi de suite.
J'espère que cela le rend plus lisible.
python 3
la version peut être utile pour les débutantsimportez d'abord les bibliothèques requises
la source
lambda x:x[0]-x[1]
.[2,3,4,5] == xrange(2,6)
, nonxrange(2,5)
. Il peut être utile de définir un nouveau type de données de plage inclusif.for key, group in groupby(enumerate(data), lambda i: i[0] - i[1]): group = list(map(itemgetter(1), group))
La solution "naïve" que je trouve au moins lisible.
la source
print([i if i[0] != i[1] else i[0] for i in group(x)])
En supposant que votre liste est triée:
la source
[j - i for i, j in enumerate(lst)]
est intelligent :-)Ici, c'est quelque chose qui devrait fonctionner, sans aucune importation nécessaire:
la source
Veuillez noter que le code utilisant
groupby
ne fonctionne pas comme indiqué dans Python 3, alors utilisez ceci.la source
Cela n'utilise pas de fonction standard - il ne fait qu'itérer sur l'entrée, mais cela devrait fonctionner:
Notez que cela nécessite que l'entrée contienne uniquement des nombres positifs dans l'ordre croissant. Vous devez valider l'entrée, mais ce code est omis pour plus de clarté.
la source
Voici la réponse que j'ai trouvée. J'écris le code pour que d'autres personnes le comprennent, donc je suis assez bavard avec les noms de variables et les commentaires.
D'abord une fonction d'aide rapide:
Et puis le code réel:
Exemple d'exécution:
Retour:
la source
>>> getranges([2, 12, 13])
Les sorties:[[12, 13]]
. Était-ce intentionnel?Production:
la source
Utiliser
groupby
etcount
deitertools
nous donne une solution courte. L'idée est que, dans une séquence croissante, la différence entre l'indice et la valeur restera la même.Afin de garder une trace de l'index, nous pouvons utiliser un itertools.count , ce qui rend le code plus propre en utilisant
enumerate
:Quelques exemples de sortie:
la source
Utilisation des listes numpy + compréhension:
Avec la fonction numpy diff, les entrées vectorielles d'entrée conséquentes dont la différence n'est pas égale à un peuvent être identifiées. Le début et la fin du vecteur d'entrée doivent être pris en compte.
Production:
Remarque: La demande selon laquelle les numéros individuels doivent être traités différemment (renvoyés en tant qu'individus et non par plages) a été omise. Ceci peut être atteint par un post-traitement supplémentaire des résultats. Habituellement, cela rendra les choses plus complexes sans en tirer aucun avantage.
la source
Une solution courte qui fonctionne sans importations supplémentaires. Il accepte tout itérable, trie les entrées non triées et supprime les éléments en double:
Exemple:
C'est la même chose que la solution de @ dansalmo que j'ai trouvée incroyable, bien qu'un peu difficile à lire et à appliquer (car elle n'est pas donnée en tant que fonction).
Notez qu'il pourrait facilement être modifié pour cracher des plages ouvertes "traditionnelles"
[start, end)
, en modifiant par exemple l'instruction return:J'ai copié cette réponse à partir d' une autre question qui a été marquée comme un double de celle-ci dans le but de la rendre plus facile à trouver (après avoir récemment cherché à nouveau ce sujet, trouvant seulement la question ici au début et n'étant pas satisfait des réponses donné).
la source
Les versions de Mark Byers , Andrea Ambu , SilentGhost , Nadia Alramli et truppo sont simples et rapides. La version 'truppo' m'a encouragé à écrire une version qui conserve le même comportement agile tout en gérant des tailles de pas autres que 1 (et des listes comme des éléments singletons qui ne s'étendent pas plus d'un pas avec une taille de pas donnée). Il est donné ici .
la source