在 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】:

如果您正在搜索myvaluemylist 中最后一次出现的索引:

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 的列表中查找某个值的第一个和最后一个索引的主要内容,如果未能解决你的问题,请参考以下文章

python 数组根据内容查找某个值的位置

在 Python 中,如何找到不是某个值的列表中第一项的索引?

Python列表查找具有接近值的元素

二分搜索算法

Django 1.9 在列表中查找属性等于某个值的对象

查找列表中某个值的位置