在 Python 的列表中查找某个值的第一个和最后一个索引
Posted
技术标签:
【中文标题】在 Python 的列表中查找某个值的第一个和最后一个索引【英文标题】:Finding first and last index of some value in a list in Python 【发布时间】:2010-10-06 01:28:25 【问题描述】:是否有任何内置方法属于列表的一部分,可以为我提供某个值的第一个和最后一个索引,例如:
verts.IndexOf(12.345)
verts.LastIndexOf(12.345)
【问题讨论】:
我也在阅读它们,但对 python 一无所知会使事情变得更加困难。我觉得它的语法很神秘。 如果您的列表已排序,那么您可能需要查看 bisect 模块 docs.python.org/3/library/bisect.html>。 在这里使用内置函数枚举和反转查看 Dikei 的精彩回答:***.com/questions/9836425/… 【参考方案1】:使用max
+ enumerate
获取最后一个元素的出现
rindex = max(i for i, v in enumerate(your_list) if v == your_value)
【讨论】:
【参考方案2】:也许是找到 last 索引的两种最有效的方法:
def rindex(lst, value):
lst.reverse()
i = lst.index(value)
lst.reverse()
return len(lst) - i - 1
def rindex(lst, value):
return len(lst) - operator.indexOf(reversed(lst), value) - 1
两者都只占用 O(1) 额外空间,并且第一个解决方案的 两个 就地反转比创建反向副本要快得多。让我们将其与之前发布的其他解决方案进行比较:
def rindex(lst, value):
return len(lst) - lst[::-1].index(value) - 1
def rindex(lst, value):
return len(lst) - next(i for i, val in enumerate(reversed(lst)) if val == value) - 1
基准测试结果,我的解决方案是红色和绿色的:
这是为了在一百万个数字的列表中搜索一个数字。 x 轴表示搜索元素的位置:0% 表示它位于列表的开头,100% 表示它位于列表的末尾。所有解决方案在位置 100% 处最快,两个 reversed
解决方案几乎没有时间,双反向解决方案需要一点时间,而反向复制需要很多时间。
仔细看看右端:
在位置 100% 处,反向复制解决方案和双反向解决方案将所有时间都花在了反转上(index()
是即时的),因此我们看到两个原地反转的速度大约是原来的 7 倍就像创建反向副本一样。
上面是lst = list(range(1_000_000, 2_000_001))
,它几乎在内存中按顺序创建了 int 对象,这对缓存非常友好。让我们在用random.shuffle(lst)
洗牌之后再做一次(可能不太现实,但很有趣):
正如预期的那样,一切都变慢了。反向复制解决方案遭受的损失最大,在 100% 时,它现在需要的时间大约是双反向解决方案的 32 倍 (!)。而enumerate
-解决方案现在是第二快的,仅次于位置 98%。
总体而言,我最喜欢operator.indexOf
解决方案,因为它是所有位置的后半部分或四分之一中最快的解决方案,如果您实际上正在为某事做rindex
,这可能是更有趣的位置。而且它只比早期位置的双反转解决方案慢一点。
在 Windows 10 Pro 1903 64 位上使用 CPython 3.9.0 64 位完成所有基准测试。
【讨论】:
请注意reverse; index; reverse
不是线程安全的。【参考方案3】:
Python 列表具有index()
方法,您可以使用该方法查找列表中项目第一次出现 的位置。请注意,list.index()
在列表中不存在该项目时引发ValueError
,因此您可能需要将其包装在try
/except
:
try:
idx = lst.index(value)
except ValueError:
idx = None
要有效地查找列表中项目最后次出现的位置(即不创建反向中间列表),您可以使用此函数:
def rindex(lst, value):
for i, v in enumerate(reversed(lst)):
if v == value:
return len(lst) - i - 1 # return the index in the original list
return None
print(rindex([1, 2, 3], 3)) # 2
print(rindex([3, 2, 1, 3], 3)) # 3
print(rindex([3, 2, 1, 3], 4)) # None
【讨论】:
【参考方案4】:s.index(x[, i[, j]])
在 s 中第一次出现 x 的索引(在索引 i 处或之后,索引 j 之前)
【讨论】:
【参考方案5】:如果您正在搜索myvalue
在mylist
中最后一次出现的索引:
len(mylist) - mylist[::-1].index(myvalue) - 1
【讨论】:
如果myvalue
不存在于mylist
中,这将抛出ValueError
。【参考方案6】:
这个方法可以比上面更优化
def rindex(iterable, value):
try:
return len(iterable) - next(i for i, val in enumerate(reversed(iterable)) if val == value) - 1
except StopIteration:
raise ValueError
【讨论】:
“优化”意味着更节省空间,但速度会慢 50%。【参考方案7】:序列有一个方法index(value)
,它返回第一次出现的索引——在你的情况下,这将是verts.index(value)
。
您可以在verts[::-1]
上运行它以找出最后一个索引。这里是len(verts) - 1 - verts[::-1].index(value)
【讨论】:
谢谢,list[::-1] 是怎么执行的?顶点[::-1]? 顺便说一句 verts[::-1] 只是反转列表,对吗?所以我必须补偿索引,对吧? 当然,它会是:len(verts) - 1 - verts[::-1].index(value) 这可以简化为 guild[::-1][0]【参考方案8】:作为一个小辅助函数:
def rindex(mylist, myvalue):
return len(mylist) - mylist[::-1].index(myvalue) - 1
【讨论】:
以上是关于在 Python 的列表中查找某个值的第一个和最后一个索引的主要内容,如果未能解决你的问题,请参考以下文章