Подтвердить что ты не робот

Как найти последнее вхождение элемента в списке Python

Скажем, у меня есть этот список:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]

Насколько мне помогло, нет встроенной функции, которая возвращает последнее вхождение строки (например, обратное к index). Итак, как я могу найти последнее вхождение "a" в данном списке?

4b9b3361

Ответ 1

Если вы на самом деле используете только отдельные буквы, как показано в вашем примере, то str.rindex будет работать str.rindex. Это вызывает ValueError если такого элемента нет, тот же класс ошибок, что и list.index. Демо-версия:

>>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
>>> ''.join(li).rindex('a')
6

Для более общего случая вы можете использовать list.index в обратном списке:

>>> len(li) - 1 - li[::-1].index('a')
6

Нарезка здесь создает копию всего списка. Это хорошо для коротких списков, но для случая, когда li очень большой, эффективность может быть лучше с ленивым подходом:

def list_rindex(li, x):
    for i in reversed(range(len(li))):
        if li[i] == x:
            return i
    raise ValueError("{} is not in list".format(x))

Однолинейная версия:

next(i for i in reversed(range(len(li))) if li[i] == 'a')

Ответ 2

Один лайнер, похожий на Ignacio, за исключением немного более простого/четкого, будет

max(loc for loc, val in enumerate(li) if val == 'a')

Мне кажется очень ясным и Pythonic: вы ищете самый высокий индекс, который содержит соответствующее значение. Никаких следов, лямбда, обратных или требуемых.

Ответ 3

Многие другие решения требуют итерации по всему списку. Это не так.

def find_last(lst, elm):
  gen = (len(lst) - 1 - i for i, v in enumerate(reversed(lst)) if v == elm)
  return next(gen, None)

Изменить: В ретроспективе это кажется ненужным волшебством. Я бы сделал что-то вроде этого:

def find_last(lst, sought_elt):
    for r_idx, elt in enumerate(reversed(lst)):
        if elt == sought_elt:
            return len(lst) - 1 - r_idx

Ответ 4

Мне нравятся ответы Вим и Игнасио. Тем не менее, я думаю, что itertools предоставляет немного более удобочитаемую альтернативу, несмотря на лямбду. (Для Python 3; для Python 2 используйте xrange вместо range).

>>> from itertools import dropwhile
>>> l = list('apples')
>>> l.index('p')
1
>>> next(dropwhile(lambda x: l[x] != 'p', reversed(range(len(l)))))
2

Это StopIteration исключение StopIteration если элемент не найден; вы можете поймать это и вызвать вместо него ValueError, чтобы заставить его вести себя как index.

Определяется как функция, избегая 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")

Это работает и для не чаров. Проверено:

>>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
3

Ответ 5

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

Ответ 6

С dict

Вы можете использовать тот факт, что словарные ключи являются уникальными, и при создании ключа с кортежами будет использоваться только последнее присвоение значения для определенного ключа. Как указано в других ответах, это хорошо для небольших списков, но создает словарь для всех уникальных значений и может быть неэффективным для больших списков.

dict(map(reversed, enumerate(li)))["a"]

6

Ответ 7

Я пришел сюда, надеясь найти, что кто-то уже выполнил работу по написанию наиболее эффективной версии list.rindex, которая предоставила полный интерфейс list.index (включая необязательные параметры start и stop). Я не нашел этого в ответах на этот вопрос, или здесь, или здесь, или . Поэтому я собрал это вместе... используя предложения из других ответов на этот и другие вопросы.

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)

Метод с использованием len(seq) - 1 - next(i for i,v in enumerate(reversed(seq)) if v == value), предложенный в нескольких других ответах, может быть более экономичным: не нужно создавать обратную копию полного списка. Но в моем (удаленном, случайном) тестировании он примерно на 50% медленнее.

Ответ 8

Используйте простой цикл:

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

Ответ 9

last_occurence=len(yourlist)-yourlist[::-1].index(element)-1

просто, как то. нет необходимости импортировать или создать функцию.

Ответ 10

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

Ответ 11

val = [1,2,2,2,2,2,4,5].

Если вам нужно найти последнее вхождение 2

last_occurence = (len(val) -1) - list(reversed(val)).index(2)

Ответ 12

Вот небольшая строка для получения последнего индекса с использованием enumerate и понимания списка:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]
[l[0] for l in enumerate(li) if l[1] == "a"][-1]

Ответ 13

from array import array
fooa = array('i', [1,2,3])
fooa.reverse()  # [3,2,1]
fooa.index(1)
>>> 2