列表中是否包含任何内置方法,这些方法可以为我提供某些值的第一个和最后一个索引,例如:
verts.IndexOf(12.345)
verts.LastIndexOf(12.345)
列表中是否包含任何内置方法,这些方法可以为我提供某些值的第一个和最后一个索引,例如:
verts.IndexOf(12.345)
verts.LastIndexOf(12.345)
Answers:
序列具有一种index(value)
返回首次出现的索引的方法-在您的情况下为verts.index(value)
。
您可以对其运行verts[::-1]
以找出最后一个索引。在这里,这将是len(verts) - 1 - verts[::-1].index(value)
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
也许找到最后一个索引的两种最有效方法:
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()
是即时的),因此我们看到两次就地反转的速度大约是创建反向副本的七倍。
以上是with的lst = list(range(1_000_000, 2_000_001))
,它几乎可以在内存中顺序创建int对象,这对缓存非常友好。在对列表进行改组后,让我们再做一次random.shuffle(lst)
(可能不太现实,但很有趣):
一切都变慢了,正如预期的那样。反向复制解决方案遭受的损失最大,现在,与双重反向解决方案相比,反向复制解决方案遭受的损失高达100%约32倍。enumerate
现在,-solution仅在定位98%之后排名第二。
总体而言,我operator.indexOf
最喜欢该解决方案,因为它是所有位置的后半部分或四分之一位置中最快的一种,如果您实际上正在rindex
做某事,那么这可能是更有趣的位置。而且它仅比早期位置的双反向解决方案慢一点。
Windows 10 Pro 1903 64位上使用CPython 3.9.0 64位完成的所有基准测试。
这种方法可以比上面更优化
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