109 votes

Trouver le premier et le dernier index d'une valeur dans une liste en Python

Y a-t-il des méthodes intégrées qui font partie des listes qui me donneraient le premier et le dernier indice d'une valeur, comme:

verts.IndexOf(12.345)
verts.LastIndexOf(12.345)

2 votes

Je les lis aussi, mais ne rien savoir du python rend les choses plus difficiles. Je trouve sa syntaxe très cryptique.

0 votes

Si vos listes sont triées, alors vous voudrez peut-être consulter le module bisect <docs.python.org/3/library/bisect.html>.

0 votes

Voir la brillante réponse de Dikei ici en utilisant les fonctions intégrées enumerate et reversed : stackoverflow.com/questions/9836425/…

159voto

SilentGhost Points 79627

Les séquences ont une méthode index(valeur) qui renvoie l'index de la première occurrence - dans votre cas ce serait verts.index(valeur).

Vous pouvez l'exécuter sur verts[::-1] pour trouver le dernier index. Ici, ce serait len(verts) - 1 - verts[::-1].index(valeur)

0 votes

Merci, comment exécutez-vous list[::-1]? verts[::-1]?

5 votes

Btw verts[::-1] inverse simplement la liste, non ? Donc je dois compenser pour l'index, non ?

16 votes

Bien sûr, ce sera : len(verts) - 1 - verts[::-1].index(value)

42voto

Stefan Pochmann Points 5022

Peut-être les deux façons les plus efficaces de trouver le dernier index:

def rindex(lst, value):
    lst.reverse()
    i = lst.index(value)
    lst.reverse()
    return len(lst) - i - 1

def rindex(lst, value):
    return len(lst) - operator.indexOf(reversed(lst), value) - 1

Les deux ne prennent que O(1) d'espace supplémentaire et les deux inversions sur place de la première solution sont beaucoup plus rapides que de créer une copie inversée. Comparons cela avec les autres solutions postées précédemment:

def rindex(lst, value):
    return len(lst) - lst[::-1].index(value) - 1

def rindex(lst, value):
    return len(lst) - next(i for i, val in enumerate(reversed(lst)) if val == value) - 1

Résultats des tests, mes solutions sont les rouges et vertes: non mélangé, plage complète

Ceci est pour rechercher un chiffre dans une liste d'un million de chiffres. L'axe des x représente l'emplacement de l'élément recherché : 0% signifie qu'il est au début de la liste, 100% signifie qu'il est à la fin de la liste. Toutes les solutions sont les plus rapides à l'emplacement 100%, avec les deux solutions reversed prenant à peu près aucun temps pour cela, la solution double-inversion prenant un peu de temps, et la copie inversée prenant beaucoup de temps.

Un regard plus attentif sur l'extrémité droite: non mélangé, partie de queue

À l'emplacement 100%, la solution de copie inversée et la solution de double inversion passent tout leur temps sur les inversions (index() est instantané), donc nous voyons que les deux inversions sur place sont environ sept fois plus rapides que la création de la copie inversée.

Ce qui précède était avec lst = list(range(1_000_000, 2_000_001)), ce qui crée pratiquement les objets int séquentiellement en mémoire, ce qui est extrêmement favorable au cache. Refaisons-le après avoir mélangé la liste avec random.shuffle(lst) (probablement moins réaliste, mais intéressant):

liste mélangée, plage complète

liste mélangée, partie de queue

Tout a beaucoup ralenti, comme prévu. La solution de copie inversée est celle qui souffre le plus, à 100% elle prend maintenant environ 32 fois (!) plus de temps que la solution de double inversion. Et la solution avec enumerate est désormais la deuxième plus rapide seulement après l'emplacement 98%.

En général, j'aime la solution avec operator.indexOf le mieux, car c'est la plus rapide pour la dernière moitié ou le dernier quart de tous les emplacements, qui sont peut-être les emplacements les plus intéressants si vous utilisez réellement rindex pour quelque chose. Et ce n'est que légèrement plus lent que la solution de double inversion dans les premiers emplacements.

Tous les tests effectués avec CPython 3.9.0 64 bits sur Windows 10 Pro 1903 64 bits.

32voto

user2669486 Points 11

Si vous recherchez l'indice de la dernière occurrence de myvalue dans mylist :

len(mylist) - mylist[::-1].index(myvalue) - 1

1 votes

Cela va déclencher une ValueError si myvalue n'est pas présent dans mylist.

13voto

Caridorc Points 2012

Comme une petite fonction d'aide :

def rindex(mylist, myvalue):
    return len(mylist) - mylist[::-1].index(myvalue) - 1

8voto

eugene y Points 37378

Les listes Python disposent de la méthode index(), que vous pouvez utiliser pour trouver la position de la première occurrence d'un élément dans une liste. Notez que list.index() déclenche une erreur ValueError lorsque l'élément n'est pas présent dans la liste, vous devrez donc l'encadrer dans un bloc try/except:

try:
    idx = lst.index(value)
except ValueError:
    idx = None

Pour trouver la position de la dernière occurrence d'un élément dans une liste de manière efficace (c'est-à-dire sans créer de liste intermédiaire inversée), vous pouvez utiliser cette fonction :

def rindex(lst, value):
    for i, v in enumerate(reversed(lst)):
        if v == value:
            return len(lst) - i - 1  # retourne l'index dans la liste originale
    return None    

print(rindex([1, 2, 3], 3))     # 2
print(rindex([3, 2, 1, 3], 3))  # 3
print(rindex([3, 2, 1, 3], 4))  # None

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X