繁体   English   中英

在 Python 的列表中查找某个值的第一个和最后一个索引

[英]Finding first and last index of some value in a list in Python

是否有任何内置方法是列表的一部分,可以给我某个值的第一个和最后一个索引,例如:

verts.IndexOf(12.345)
verts.LastIndexOf(12.345)

序列有一个方法index(value) ,它返回第一次出现的索引 - 在你的情况下这将是verts.index(value)

您可以在verts[::-1]上运行它以找出最后一个索引。 在这里,这将是len(verts) - 1 - verts[::-1].index(value)

如果您要搜索mylist最后一次出现的myvalue的索引:

len(mylist) - mylist[::-1].index(myvalue) - 1

使用i1 = yourlist.index(yourvalue)i2 = yourlist.rindex(yourvalue).

我对我的这个错误答案一直感到不高兴,但这似乎是人们正在寻找的东西。 这里是找到的最后一个索引的解决方案i你的价值的12.345您的列表verts

for i, v in enumerate(reversed(verts)):
    if v == '12.345':
        break

也许找到最后一个索引的两种最有效的方法:

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 位完成的所有基准测试。

作为一个小辅助函数:

def rindex(mylist, myvalue):
    return len(mylist) - mylist[::-1].index(myvalue) - 1

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

正确的解决方案是执行“C 级反向循环匹配”的解决方案。

在伪 C 代码中:


for (int i = len(list) -1; i >= 0; i--)
    if list[i] == value:
        return i
raise NotFound

在Python中,正确的解法应该是:

def rindex(lst, value):
    # reversed is a buitin backward iterator
    # operator.indexOf can handle this iterator
    # if value is not Found it raises
    #    ValueError: sequence.index(x): x not in sequence
    _ = operator.indexOf(reversed(lst), value)
    # we must fix the resersed index
    return len(lst) - _ - 1

但是内置一个反向索引会更好。

这个方法可以比上面更优化

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
s.index(x[, i[, j]])

x 在 s 中首次出现的索引(在索引 i 处或之后和索引 j 之前)

使用max + enumerate获取最后一个元素出现

rindex = max(i for i, v in enumerate(your_list) if v == your_value)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM