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

如何在Python列表中查找项目的最后一次出现,python,list,last-occurrence,Python,List,Last Occurrence,假设我有这个清单: li = ["a", "b", "a", "c", "x", "d", "a", "6"] 据帮助所示,没有一个内置函数返回字符串的最后一次出现(如index的相反)。因此,基本上,我如何才能找到给定列表中最后出现的“a”。如果您实际上只使用了示例中所示的单个字母,那么这将非常方便。这会引发一个ValueError,如果没有此类项,则会引发与list.index相同的错误类别。演示: >>> (x for x in reversed([y for y in

假设我有这个清单:

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

据帮助所示,没有一个内置函数返回字符串的最后一次出现(如
index
的相反)。因此,基本上,我如何才能找到给定列表中最后出现的
“a”

如果您实际上只使用了示例中所示的单个字母,那么这将非常方便。这会引发一个
ValueError
,如果没有此类项,则会引发与
list.index
相同的错误类别。演示:

>>> (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
>>> 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')
我两个都喜欢。然而,我认为,
itertools
提供了一种更具可读性的选择,尽管lambda。(对于Python3;对于Python2,使用
xrange
而不是
range

如果找不到项目,这将引发
StopIteration
异常;您可以捕捉到这一点,并引发一个
ValueError
,使其正常工作

定义为函数,避免使用
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")
它也适用于非chars。测试:

>>> rindex(['apples', 'oranges', 'bananas', 'apples'], 'apples')
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

一个类似伊格纳西奥的单行程序,只是简单一点/更清晰一点

max(loc for loc, val in enumerate(li) if val == 'a')
对我来说,这似乎很清楚,也很像Python:您正在寻找包含匹配值的最高索引。无需nexts、lambdas、reverseds或itertools

使用一个简单的循环:

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

我来到这里,希望有人已经完成了编写最有效版本的
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代表i,v在enumerate(reversed(seq))if v==value)
的技术可以更节省空间:它不需要创建完整列表的反向副本。但在我的(随意的)测试中,速度大约慢了50%。

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

如果您需要查找2的最后一次出现


last\u occurrence=(len(val)-1)-列表(reversed(val))。索引(2)

这里有一个小的线性关系,用于获取最后一个索引、使用和列表理解:

li = ["a", "b", "a", "c", "x", "d", "a", "6"]
[l[0] for l in enumerate(li) if l[1] == "a"][-1]
就这么简单。无需导入或创建函数。

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

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

6

如果列表较小,则可以计算所有索引并返回最大的:

index = max(i for i, x in enumerate(elements) if x == 'foo')

为什么不将
反转(枚举(li))
?因为我在3年前没有遇到过它。奇怪的是,
反转(枚举(li))
会导致一个错误,读取到反转()的
参数必须是一个序列
!它说对于
reversed((在enumarete(li)中y代表y))
也有意义,
reversed()
通常不能在迭代器上操作,包括生成器。因此,
枚举(reversed(li))
调整枚举元组的索引组件是一种避免创建列表副本的解决方法。正如@Isaac所指出的,它总是迭代li的所有N个元素。这是完美的。对于大数据集可能不太理想,但对于小数据量却很好。一个显著的缺点是,您总是会迭代到h整个列表。你应该在你的答案中强调这一点。YMMV,但对于这个例子,
len(li)-next(i代表i,v在枚举中(反转(li),1)如果v='a')
比mether快一点是
str.rindex()
,有没有理由不
list.rindex()
?@Chris Rands:比
range(len(li)-1,-1更好)
或者是
反向(range(len(li))
或者
范围(len(li))[:-1]
(它们也大致相同,不同于
反向
和反向切片之间的大多数比较;现代的Py3
范围
可以反向切片,以生成另一个向后运行的惰性
范围
,因此性能相同)。看起来wim和前者一样。@ShadowRanger是的,wim在我写那条评论后编辑了他的答案。这是当时的答案,我将删除我之前的评论(和这一条),以避免混淆Python版本
next(len(a)-i-1表示i,x在枚举中(反向(a)),如果x==3)
Python3现在允许在
next
中使用默认的arg,因此您可以取消
try…除了
@PM2Ring之外,我不知道您为什么要在这里使用默认的arg。然后您需要有一个
if
语句,并在其中提出一个
ValueError
。(回想一下,我们正试图精确复制
索引
API,这意味着如果找不到该项,将引发
ValueError
)在此上下文中使用
try
更为惯用,而且我猜,效率更高。公平调用。可能会提出
indexer
而不是
ValueError
,以与
.index
一致?
indexer
用于传递不正确的索引。将缺少的值传递给
index
会生成
值错误
。我怀疑区别在于C循环和Python循环。
last_occurence=len(yourlist)-yourlist[::-1].index(element)-1
dict(map(reversed, enumerate(li)))["a"]

6
lastIndexOf = lambda array, item: len(array) - (array[::-1].index(item)) - 1
index = max(i for i, x in enumerate(elements) if x == 'foo')