如何在Python列表中查找项的最后一次出现

Sha*_*kan 64 python list last-occurrence

说我有这个清单:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]
Run Code Online (Sandbox Code Playgroud)

至于帮助告诉我,没有内置函数返回最后一次出现的字符串(如反之index).基本上,我怎样才能找到"a"给定列表中的最后一次出现?

wim*_*wim 75

如果您实际上只使用了示例中显示的单个字母,那么str.rindex就可以轻松工作.ValueError如果没有这样的项目,则会引发一个相同的错误类别list.index.演示:

>>> li = ["a", "b", "a", "c", "x", "d", "a", "6"]
>>> ''.join(li).rindex('a')
6
Run Code Online (Sandbox Code Playgroud)

对于更一般的情况,您可以list.index在反向列表中使用:

>>> len(li) - 1 - li[::-1].index('a')
6
Run Code Online (Sandbox Code Playgroud)

此处的切片会创建整个列表的副本.这对于短名单来说很好,但对于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))
Run Code Online (Sandbox Code Playgroud)

单线版:

next(i for i in reversed(range(len(li))) if li[i] == 'a')
Run Code Online (Sandbox Code Playgroud)

  • 有`str.rindex()`,任何原因都没有`list.rindex()`? (8认同)
  • YMMV,但对于此示例,len(li)-next(i for i,v枚举(reversed(li),1),如果v =='a')`对我来说快一点 (2认同)
  • @Chris_Rands:比 `range(len(li)-1, -1, -1)` 更好的是 `reversed(range(len(li)))` 或 `range(len(li))[::-1 ]`(它们也大致等效,与“reversed”和反向切片之间的大多数比较不同;现代 Py3“range”可以反向切片以生成另一个向后运行的惰性“range”,因此它的性能相同)。看起来 wim 选择了前者。 (2认同)

alc*_*lde 32

像Ignacio一样的单线,除了更简单/更清晰之外

max(loc for loc, val in enumerate(li) if val == 'a')
Run Code Online (Sandbox Code Playgroud)

对我来说似乎非常清楚和Pythonic:你正在寻找包含匹配值的最高索引.不需要nexts,lambdas,reverseds或itertools.

  • 正如@Isaac指出的那样,它总是遍历li的所有N个元素. (7认同)
  • 使用 **default=None** 来避免错误“ValueError: max() arg is anempty sequence” ```max((loc for loc, val in enumerate(li) if val == 'a'), default=无)``` (2认同)

Isa*_*aac 16

许多其他解决方案需要遍历整个列表.事实并非如此.

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

编辑:事后看来,这似乎是不必要的魔法.我会做这样的事情:

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


sen*_*rle 7

我喜欢wimIgnacio的答案.但是,我认为itertools提供了一个稍微更具可读性的替代方案,尽管lambda.(对于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
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

它也适用于非字符.测试:

>>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
3
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 6

>>> (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
Run Code Online (Sandbox Code Playgroud)

  • 因为3年前我没有想到它. (23认同)
  • 为什么不`reversed(enumerate(li))`? (2认同)
  • 有意义的是,reverse()`通常不能对迭代器进行操作,包括生成器.因此,`enumerate(reversed(li))`和调整枚举元组的索引组件是一种避免创建列表副本的解决方法. (2认同)

小智 6

last_occurence=len(yourlist)-yourlist[::-1].index(element)-1
Run Code Online (Sandbox Code Playgroud)

就这么简单。无需导入或创建函数。


piR*_*red 5

dict

您可以使用字典键是唯一的这一事实,并且在使用元组构建一个元组时,只会使用特定键的最后一个值分配。正如其他答案中所述,这对于小列表来说很好,但它为所有唯一值创建了一个字典,对于大列表可能效率不高。

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

6
Run Code Online (Sandbox Code Playgroud)