对于一个列表["foo", "bar", "baz"]
和列表中的一个项目"bar"
,我如何在Python中得到它的索引(1)?
>>> ["foo", "bar", "baz"].index("bar")
1
参考资料。Data Structures > More on Lists
请注意,虽然这可能是回答这个问题的最干净的方法,但 "index "是 "list "API的一个相当弱的组成部分,我不记得我最后一次愤怒地使用它是什么时候。有人在评论中向我指出,由于这个答案被大量引用,它应该变得更加完整。关于list.index
的一些注意事项如下。可能值得先看一下它的文档串。
>>> print(list.index.__doc__)
L.index(value, [start, [stop]]) -> integer -- return first index of value.
Raises ValueError if the value is not present.
一个 "index "调用依次检查列表中的每个元素,直到找到一个匹配的元素。如果你的列表很长,而且你不知道它在列表中的大致位置,这种搜索可能成为一个瓶颈。在这种情况下,你应该考虑采用不同的数据结构。请注意,如果你大致知道在哪里可以找到匹配,你可以给index
一个提示。例如,在这个片段中,l.index(999_999, 999_990, 1_000_000)
比直接l.index(999_999)
快了大约五个数量级,因为前者只需要搜索10个条目,而后者要搜索一百万个。
>>> import timeit
>>> timeit.timeit('l.index(999_999)', setup='l = list(range(0, 1_000_000))', number=1000)
9.356267921015387
>>> timeit.timeit('l.index(999_999, 999_990, 1_000_000)', setup='l = list(range(0, 1_000_000))', number=1000)
0.0004404920036904514
对 "index "的调用按顺序搜索列表,直到找到一个匹配项,然后停止。如果你希望需要更多匹配项的索引,你应该使用列表理解,或者生成器表达式。
>>> [1, 1].index(1)
0
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> next(g)
0
>>> next(g)
2
在大多数地方,我曾经使用过 "index",现在我使用列表理解或生成器表达式,因为它们更具有通用性。所以,如果你考虑使用index
,请看看这些优秀的python特性。
对index
的调用会导致ValueError
,如果该项目不存在。
>>> [1, 1].index(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 2 is not in list
如果该项目可能不存在于列表中,你应该选择
1.先用item in my_list
检查它(干净、可读的方法),或者
2.将index'调用包裹在一个
try/except'块中,该块可以捕获`ValueError'(可能更快,至少当要搜索的列表很长,并且项目通常是存在的)。
大多数答案都解释了如何找到个单一的索引,但如果项目在列表中多次出现,它们的方法就不会返回多个索引。
使用enumerate()
。
for i, j in enumerate(['foo', 'bar', 'baz']):
if j == 'bar':
print(i)
index()
函数只返回第一次出现的情况,而enumerate()
则返回所有出现的情况。
作为一个列表的理解。
[i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar']
这里'也是另一个小解决方案,用itertools.count()
(这和枚举的方法差不多)。
from itertools import izip as zip, count # izip for maximum efficiency
[i for i, j in zip(count(), ['foo', 'bar', 'baz']) if j == 'bar']
对于较大的列表,这比使用enumerate()
更有效。
$ python -m timeit -s "from itertools import izip as zip, count" "[i for i, j in zip(count(), ['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 174 usec per loop
$ python -m timeit "[i for i, j in enumerate(['foo', 'bar', 'baz']*500) if j == 'bar']"
10000 loops, best of 3: 196 usec per loop
index()
返回值的第一个索引!
| index(...) | L.index(value, [start, [stop]] -> integer -- 返回值的第一个索引
def all_indices(value, qlist):
indices = []
idx = -1
while True:
try:
idx = qlist.index(value, idx+1)
indices.append(idx)
except ValueError:
break
return indices
all_indices("foo", ["foo","bar","baz","foo"])
如果元素不在列表中,就会出现问题。 这个函数可以处理这个问题。
# if element is found it returns index of element else returns None
def find_element_in_list(element, list_element):
try:
index_element = list_element.index(element)
return index_element
except ValueError:
return None
这里提出的所有功能都重现了固有的语言行为,但却掩盖了'发生了什么。
[i for i in range(len(mylist)) if mylist[i]==myterm] # get the indices
[each for each in mylist if each==myterm] # get the items
mylist.index(myterm) if myterm in mylist else None # get the first index and fail quietly
如果语言自己提供方法来做你想要的事情,为什么要写一个带有异常处理的函数呢?
在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
这样做的缺点是,你可能需要检查返回的值是是
还是不是
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)
如果你有熊猫,你可以很容易地通过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
如果你只想要索引,索引属性会返回一系列的整数。
>>> series[series == 'bar'].index
Int64Index([1, 3], dtype='int64')
如果你想把它们放在一个 list 或 tuple 中,只需把它们传递给构造函数即可。
>>> list(series[series == 'bar'].index)
[1, 3]
是的,你也可以用枚举来理解列表,但在我看来,这并不优雅--你在 Python 中做平等性测试,而不是让 C 语言中的内置代码来处理它。
>>> [i for i, value in enumerate(l) if value == 'bar']
[1, 3]
XY问题问的是你的尝试性解决方案,而不是你的实际问题。
为什么你认为你需要列表中元素的索引?
如果你已经知道了这个值,为什么还要关心它在列表中的位置?
如果值不在那里,捕捉ValueError
是相当啰嗦的--我更喜欢避免这样。
无论如何,我通常会在列表上迭代,所以我通常会保留一个指针,指向任何有趣的信息,得到[index with enumerate.][2] 。
如果你正在进行数据挖掘,你可能应该使用 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
在 Lib/tarfile.py 中,与 distutils 类似,可以获得一个项目的切片。
members = members[:members.index(tarinfo)]
在 Lib/pickletools.py 中。
numtopop = before.index(markobject)
这些用法似乎有一个共同点,那就是它们似乎都是在大小受限的列表上进行操作(因为list.index
的查找时间为O(n),所以很重要),而且它们'主要用于解析(和Idle的UI)。
虽然也有用例,但相当不常见。 如果你发现自己在寻找这个答案,问问自己,你所做的是否是语言为你的用例提供的工具的最直接用法。
1:
所有使用[zip
][1]函数的索引。
get_indexes = lambda x, xs: [i for (y, i) in zip(xs, range(len(xs))) if x == y]
print get_indexes(2, [1, 2, 3, 4, 5, 6, 3, 2, 3, 2])
print get_indexes('f', 'xsfhhttytffsafweef')
使用enumerate(alist)可以存储第一个元素(n),当元素x等于你所寻找的元素时,它就是列表的索引。
>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>
这个函数将 item 和 list 作为参数,并返回 item 在 list 中的位置,就像我们之前看到的那样。
def indexlist(item2find, list_or_string):
"Returns all indexes of an item in a list or a string"
return [n for n,item in enumerate(list_or_string) if item==item2find]
print(indexlist("1", "010101010"))
产出
[1, 3, 5, 7]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
产出:
0
4
def indices(l, val):
"""Always returns a list containing the indices of val in the_list"""
retval = []
last = 0
while val in l[last:]:
i = l[last:].index(val)
retval.append(last + i)
last += i + 1
return retval
l = ['bar','foo','bar','baz','bar','bar']
q = 'bar'
print indices(l,q)
print indices(l,'bat')
print indices('abcdaababb','a')
当粘贴到一个交互式的python窗口中时。
Python 2.7.6 (v2.7.6:3a1db0d2747e, Nov 10 2013, 00:42:54)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def indices(the_list, val):
... """Always returns a list containing the indices of val in the_list"""
... retval = []
... last = 0
... while val in the_list[last:]:
... i = the_list[last:].index(val)
... retval.append(last + i)
... last += i + 1
... return retval
...
>>> l = ['bar','foo','bar','baz','bar','bar']
>>> q = 'bar'
>>> print indices(l,q)
[0, 2, 4, 5]
>>> print indices(l,'bat')
[]
>>> print indices('abcdaababb','a')
[0, 4, 5, 7]
>>>
在经历了一年的低头开发python之后,我对自己最初的答案感到有些尴尬,所以为了澄清事实,当然可以使用上面的代码,然而,更习以为常的方法是使用list comprehension,以及enumerate(函数)。 但是,要想得到同样的行为,多的方法是使用list comprehension,以及enumerate()函数。
就像这样。
def indices(l, val):
"""Always returns a list containing the indices of val in the_list"""
return [index for index, value in enumerate(l) if value == val]
l = ['bar','foo','bar','baz','bar','bar']
q = 'bar'
print indices(l,q)
print indices(l,'bat')
print indices('abcdaababb','a')
将其粘贴到交互式的python窗口中,就会产生:
Python 2.7.14 |Anaconda, Inc.| (default, Dec 7 2017, 11:07:58)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def indices(l, val):
... """Always returns a list containing the indices of val in the_list"""
... return [index for index, value in enumerate(l) if value == val]
...
>>> l = ['bar','foo','bar','baz','bar','bar']
>>> q = 'bar'
>>> print indices(l,q)
[0, 2, 4, 5]
>>> print indices(l,'bat')
[]
>>> print indices('abcdaababb','a')
[0, 4, 5, 7]
>>>
。
Python 2.7.14 |Anaconda, Inc.| (default, Dec 7 2017, 11:07:58)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def indices(l, val):
... """Always returns a list containing the indices of val in the_list"""
... return [index for index, value in enumerate(l) if value == val]
...
>>> l = ['bar','foo','bar','baz','bar','bar']
>>> q = 'bar'
>>> print indices(l,q)
[0, 2, 4, 5]
>>> print indices(l,'bat')
[]
>>> print indices('abcdaababb','a')
[0, 4, 5, 7]
>>>
现在,在回顾了这个问题和所有的答案之后,我意识到这正是[FMc][1]在他的[早期答案][2]中所建议的。 在我最初回答这个问题的时候,我甚至没有看到*那个答案,因为我没有理解它。 我希望我这个有点啰嗦的例子能帮助大家理解。
如果上面的单行代码对你来说仍然是*没有意义的,我强烈建议你在Google上搜索'python list comprehension'。 并花几分钟时间熟悉一下。 它只是众多强大功能中的一个,它使使用Python开发代码成为一种乐趣。
[1]: https://stackoverflow.com/users/55857/fmc [2]: https://stackoverflow.com/questions/176918/finding-the-index-of-an-item-given-a-list-containing-it-in-python/17300987#17300987
FMc 和 user7177 的答案的一个变体将给出一个可以返回任何条目的所有索引的 dict。
>>> a = ['foo','bar','baz','bar','any', 'foo', 'much']
>>> l = dict(zip(set(a), map(lambda y: [i for i,z in enumerate(a) if z is y ], set(a))))
>>> l['foo']
[0, 5]
>>> l ['much']
[6]
>>> l
{'baz': [2], 'foo': [0, 5], 'bar': [1, 3], 'any': [4], 'much': [6]}
>>>
你也可以把它作为一个单行线来获取一个条目的所有指数。 虽然我使用了set(a)来减少lambda的调用次数,但不能保证效率。