Dis que j'ai cette liste:
li = ["a", "b", "a", "c", "x", "d", "a", "6"]
Pour ce qui est de l'aide, il n'y a pas de fonction intégrée qui retourne la dernière occurrence d'une chaîne (comme l'inverse de index
). Donc, en gros, comment trouver la dernière occurrence de "a"
dans la liste donnée?
Si vous n'utilisez que des lettres simples, comme indiqué dans votre exemple, alors str.rindex
fonctionnerait facilement. Cela déclenche une ValueError
s'il n'y a pas d'élément de ce type, la même classe d'erreur que list.index
déclencherait. Démo:
>>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
>>> ''.join(li).rindex('a')
6
Pour le cas plus général, vous pouvez utiliser list.index
dans la liste inversée:
>>> len(li) - 1 - li[::-1].index('a')
6
Le découpage ici crée un copy de la liste entière. C'est bien pour les listes courtes, mais dans le cas où li
est très grand, l'efficacité peut être meilleure avec une approche paresseuse:
def list_rindex(li, x):
for i in reversed(range(len(li))):
if li[i] == x:
return x
raise ValueError("{} is not in list".format(x))
Version monocouche:
next(i for i in reversed(range(len(li))) if li[i] == 'a')
Un one-line qui ressemble à Ignacio, sauf qu’un peu plus simple/plus clair serait
max(loc for loc, val in enumerate(li) if val == 'a')
Cela me semble très clair et Pythonic: vous recherchez l'index le plus élevé contenant une valeur correspondante. Pas de liens, lambdas, inversés ou outils nécessaires.
Beaucoup des autres solutions nécessitent une itération sur toute la liste. Cela ne veut pas.
def find_last(lst, Elm):
gen = (len(lst) - 1 - i for i, v in enumerate(reversed(lst)) if v == Elm)
return next(gen, None)
Edit: Avec le recul, cela semble être une magie inutile. Je ferais quelque chose comme ça à la place:
def find_last(lst, sought_elt):
for r_idx, elt in enumerate(reversed(lst)):
if elt == sought_elt:
return len(lst) - 1 - r_idx
J'aime les réponses de wim et de Ignacio . Cependant, je pense que itertools
fournit une alternative légèrement plus lisible, nonobstant lambda. (Pour Python 3; pour Python 2, utilisez xrange
au lieu de range
).
>>> from itertools import dropwhile
>>> l = list('apples')
>>> l.index('p')
1
>>> next(dropwhile(lambda x: l[x] != 'p', reversed(range(len(l)))))
2
Cela déclenchera une exception StopIteration
si l'élément n'est pas trouvé; vous pouvez attraper cela et lever une ValueError
à la place, pour que cela se comporte comme index
.
Défini en tant que fonction, en évitant le raccourci lambda
:
def rindex(lst, item):
def index_ne(x):
return lst[x] != item
try:
return next(dropwhile(index_ne, reversed(range(len(lst)))))
except StopIteration:
raise ValueError("rindex(lst, item): item not in list")
Cela fonctionne aussi pour les non-personnages. Testé:
>>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
3
>>> (x for x in reversed([y for y in enumerate(li)]) if x[1] == 'a').next()[0]
6
>>> len(li) - (x for x in (y for y in enumerate(li[::-1])) if x[1] == 'a').next()[0] - 1
6
Vous pouvez utiliser le fait que les clés de dictionnaire sont uniques et que, lors de la construction avec des nuplets, seule la dernière affectation d’une valeur pour une clé particulière sera utilisée. Comme indiqué dans d'autres réponses, cela convient aux petites listes, mais il crée un dictionnaire pour toutes les valeurs uniques et peut ne pas être efficace pour les grandes listes.
dict(map(reversed, enumerate(li)))["a"]
6
Je suis venu ici dans l'espoir de trouver quelqu'un qui avait déjà écrit la version la plus efficace de list.rindex
, qui fournit l'interface complète de list.index
(y compris les paramètres optionnels start
et stop
). Je n'ai pas trouvé cela dans les réponses à cette question, ou ici ou ici ou ici . Donc, j'ai moi-même mis cela en place ... en utilisant les suggestions d'autres réponses à cette question et aux autres.
def rindex(seq, value, start=None, stop=None):
"""L.rindex(value, [start, [stop]]) -> integer -- return last index of value.
Raises ValueError if the value is not present."""
start, stop, _ = slice(start, stop).indices(len(seq))
if stop == 0:
# start = 0
raise ValueError('{!r} is not in list'.format(value))
else:
stop -= 1
start = None if start == 0 else start - 1
return stop - seq[stop:start:-1].index(value)
La technique utilisant len(seq) - 1 - next(i for i,v in enumerate(reversed(seq)) if v == value)
, suggérée dans plusieurs autres réponses, peut être plus efficace en termes d'espace: elle n'a pas besoin de créer une copie inversée de la liste complète. Mais dans mes tests (désinvoltes, occasionnels), il est environ 50% plus lent.
Utilisez une simple boucle:
def reversed_index(items, value):
for pos, curr in enumerate(reversed(items)):
if curr == value:
return len(items) - pos - 1
raise ValueError("{0!r} is not in list".format(value))
last_occurence=len(yourlist)-yourlist[::-1].index(element)-1
tout aussi facile que cela. Pas besoin d'importer ou de créer une fonction.
Voici un petit guide pour obtenir le dernier index en utilisant enumerate
et une liste de compréhension:
li = ["a", "b", "a", "c", "x", "d", "a", "6"]
[l[0] for l in enumerate(li) if l[1] == "a"][-1]
from array import array
fooa = array('i', [1,2,3])
fooa.reverse() # [3,2,1]
fooa.index(1)
>>> 2
def rindex(lst, val):
try:
return next(len(lst)-i for i, e in enumerate(reversed(lst), start=1) if e == val)
except StopIteration:
raise ValueError('{} is not in list'.format(val))