说我有这个清单:
li = ["a", "b", "a", "c", "x", "d", "a", "6"]
据帮助显示,没有内置函数返回字符串的最后一次出现(如的反向index
)。因此,基本上,如何找到"a"
给定列表中的最后一个出现?
Answers:
如果您实际上仅使用示例中显示的单个字母,则将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')
str.rindex()
,有没有原因list.rindex()
吗?
range(len(li)-1, -1, -1)
“reversed(range(len(li)))
或”更好range(len(li))[::-1]
(它们也大致相等,不像大多数与reversed
反向切片之间的比较;现代Py3range
可以反向切片,以使另一个懒惰range
向后运行,因此性能相同)。好像wim跟前者一起去了。
next(len(a)-i-1 for i, x in enumerate(reversed(a)) if x == 3)
像伊格纳西奥(Ignacio)一样的单线飞机会更简单/更清晰
max(loc for loc, val in enumerate(li) if val == 'a')
在我看来,这似乎很清楚且具有Python风格:您正在寻找包含匹配值的最高索引。不需要下一步,lambda,reverses或itertools。
许多其他解决方案都需要遍历整个列表。这不是。
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
>>> (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
reversed(enumerate(li))
呢?
reversed(enumerate(li))
导致读取错误argument to reversed() must be a sequence
!它也说reversed((y for y in enumarete(li))
!
reversed()
通常不能在迭代器(包括生成器)上运行,这是有道理的。因此,enumerate(reversed(li))
调整枚举元组的索引组件是一种避免创建列表副本的解决方法。
我都喜欢 WIM的和伊格纳西奥的答案。但是,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
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
next
,因此您可以消除try... except
if
声明并提出一个ValueError
要点。(回想一下,我们正在尝试index
精确地复制API,这意味着ValueError
如果找不到该项目,则会引发一个。)try
在这种情况下使用会更加惯用,我想会更有效。
IndexError
而不是ValueError
与之保持一致.index
?
IndexError
用于传递错误的索引。传递缺失值以index
生成ValueError
。
我来到这里的目的是希望发现有人已经完成了的最高效版本的编写工作,该版本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%。
使用一个简单的循环:
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))
len(li) - next(i for i, v in enumerate(reversed(li), 1) if v == 'a')
对我来说要快一些