在 Python 中找到一个给定列表的项目的索引
对于列表 ["foo", "bar", "baz"] 和列表中的项目 "bar",在 Python 中获取其索引 (1) 的最简洁方法是什么?
好吧,当然,有 index 方法,它返回第一次出现的索引:
>>> l = ["foo", "bar", "baz"]
>>> l.index('bar')
1
这种方法有几个问题:
- 如果该值不在列表中,您将获得
ValueError
- 如果列表中有多个值,则只能获取第一个的索引
没有值
如果该值可能丢失,您需要捕获ValueError。
您可以使用这样的可重用定义来做到这一点:
def index(a_list, value):
try:
return a_list.index(value)
except ValueError:
return None
并像这样使用它:
>>> print(index(l, 'quux'))
None
>>> print(index(l, 'bar'))
1
这样做的缺点是您可能会检查返回值是is 还是is not None:
result = index(a_list, value)
if result is not None:
do_something(result)
列表中有多个值
如果你可以有更多的出现,你将不会通过list.index获得完整的信息:
>>> l.append('bar')
>>> l
['foo', 'bar', 'baz', 'bar']
>>> l.index('bar') # nothing at index 3?
1
您可以将索引枚举到列表中:
>>> [index for index, v in enumerate(l) if v == 'bar']
[1, 3]
>>> [index for index, v in enumerate(l) if v == 'boink']
[]
如果你没有出现,你可以用布尔检查结果来检查,或者如果你循环结果,什么都不做:
indexes = [index for index, v in enumerate(l) if v == 'boink']
for index in indexes:
do_something(index)
使用 pandas 更好地处理数据
如果您有 pandas,则可以使用 Series 对象轻松获取此信息:
>>> import pandas as pd
>>> series = pd.Series(l)
>>> series
0 foo
1 bar
2 baz
3 bar
dtype: object
比较检查将返回一系列布尔值:
>>> series == 'bar'
0 False
1 True
2 False
3 True
dtype: bool
通过下标符号将该系列布尔值传递给该系列,您将获得匹配的成员:
>>> series[series == 'bar']
1 bar
3 bar
dtype: object
如果只需要索引,则 index 属性返回一系列整数:
>>> series[series == 'bar'].index
Int64Index([1, 3], dtype='int64')
如果您希望它们在列表或元组中,只需将它们传递给构造函数即可:
>>> list(series[series == 'bar'].index)
[1, 3]
是的,您也可以将列表推导式与 enumerate 一起使用,但在我看来,这并不优雅 - 您正在 Python 中进行相等性测试,而不是让用 C 编写的内置代码来处理它:
>>> [i for i, value in enumerate(l) if value == 'bar']
[1, 3]
XY 问题是询问您尝试的解决方案,而不是您的实际问题。
为什么你认为你需要给定列表中的元素的索引?
如果您已经知道值,为什么还要关心它在列表中的位置?
如果该值不存在,捕获 ValueError 会相当冗长 - 我更愿意避免这种情况。
我通常会遍历列表,所以我通常会保留指向任何有趣信息的指针,获取index with enumerate.
如果您正在处理数据,您可能应该使用 pandas - 它拥有比我展示的纯 Python 变通方法更优雅的工具。
我不记得自己需要list.index。但是,我浏览了 Python 标准库,发现它有一些出色的用途。
在idlelib 中有很多很多用途,用于 GUI 和文本解析。
keyword 模块使用它来查找模块中的注释标记,以通过元编程自动重新生成其中的关键字列表。
在 Lib/mailbox.py 中,它似乎像使用有序映射一样使用它:
key_list[key_list.index(old)] = new
和
del key_list[key_list.index(key)]
在lib/http/cookiejar.py中,好像是用来获取下个月的:
mon = MONTHS_LOWER.index(mon.lower())+1
在类似于 distutils 的 Lib/tarfile.py 中获取一个项目的切片:
members = members[:members.index(tarinfo)]
在 Lib/pickletools.py 中:
numtopop = before.index(markobject)
这些用法的共同点似乎是它们似乎在限制大小的列表上运行(很重要,因为 list.index 的 O(n) 查找时间),并且它们主要用于解析(和 UI 中的空闲的情况)。
虽然有它的用例,但它们并不常见。如果您发现自己正在寻找这个答案,请问问自己,您所做的是否是最直接地使用该语言为您的用例提供的工具。