查找给定列表中包含Python项的项的索引

对于列表["foo","bar","baz"]和列表"bar"中的项,如何在Python中获得它的索引(1)?


1
2
>>> ["foo","bar","baz"].index("bar")
1

参考文献:数据结构>更多关于列表

警告遵循

请注意,虽然这可能是回答所问问题的最干净的方法,但indexlist API的一个相当弱的组件,我不记得上次愤怒地使用它是什么时候了。我在评论中指出,因为这个答案被大量引用,所以应该做得更完整。下面是关于list.index的一些注意事项。可能值得先看看它的文档字符串:

1
2
3
>>> 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)大约快5个数量级,因为前者只搜索10个条目,而后者搜索100万个:

1
2
3
4
5
>>> 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
2
3
4
5
6
7
8
9
>>> [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
2
3
4
>>> [1, 1].index(2)
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
ValueError: 2 is not in list

如果项目可能不在列表中,您也应该这样做

首先使用item in my_list(干净、可读的方法)或将index调用封装在一个try/except块中,该块捕获ValueError(可能更快,至少当要搜索的列表很长,而且通常存在该项时)。


在学习Python时,有一件事非常有用,那就是使用交互式帮助函数:

1
2
3
4
5
6
7
8
9
10
>>> help(["foo","bar","baz"])
Help on list object:

class list(object)
 ...

 |
 |  index(...)
 |      L.index(value, [start, [stop]]) -> integer -- return first index of value
 |

这通常会引导您找到您正在寻找的方法。


大多数答案都解释了如何查找单个索引,但是如果条目多次出现在列表中,它们的方法不会返回多个索引。使用enumerate():

1
2
3
for i, j in enumerate(['foo', 'bar', 'baz']):
    if j == 'bar':
        print(i)

函数只返回第一个事件,而enumerate()返回所有事件。

作为一个列表理解:

1
[i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar']

这里还有一个小的解决方案与itertools.count()(这是非常相同的方法枚举):

1
2
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()更有效:

1
2
3
4
$ 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


获取所有索引:

1
 indexes = [i for i,x in enumerate(xs) if x == 'foo']


index()返回第一个值索引!

| index(...)
| L.index(value, [start, [stop]]) -> integer -- return first index of value

1
2
3
4
5
6
7
8
9
10
11
12
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"])


如果元素不在列表中,就会出现问题。这个函数处理的问题:

1
2
3
4
5
6
7
8
# 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

1
2
3
a = ["foo","bar","baz",'bar','any','much']

indexes = [index for index in range(len(a)) if a[index] == 'bar']


您必须设置一个条件来检查正在搜索的元素是否在列表中

1
2
3
4
if 'your_element' in mylist:
    print mylist.index('your_element')
else:
    print None


这里提出的所有函数都重现了固有的语言行为,但都模糊了正在发生的事情。

1
2
3
4
5
[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

如果语言本身提供了实现所需功能的方法,为什么要编写带有异常处理的函数呢?


如果你想要所有的索引,那么你可以使用NumPy:

1
2
3
4
5
6
7
8
import numpy as np

array = [1, 2, 1, 3, 4, 5, 1]
item = 1
np_array = np.array(array)
item_index = np.where(np_array==item)
print item_index
# Out: (array([0, 2, 6], dtype=int64),)

这是一个清晰易读的解决方案。


Finding the index of an item given a list containing it in Python

For a list ["foo","bar","baz"] and an item in the list "bar", what's the cleanest way to get its index (1) in Python?

当然,有index方法,它返回第一次出现的索引:

1
2
3
>>> l = ["foo","bar","baz"]
>>> l.index('bar')
1

这种方法有几个问题:

如果该值不在列表中,您将得到ValueError如果列表中有多个值,则只能得到第一个值的索引

没有值

如果该值可能丢失,则需要捕获ValueError

你可以这样使用一个可重用的定义:

1
2
3
4
5
def index(a_list, value):
    try:
        return a_list.index(value)
    except ValueError:
        return None

像这样使用:

1
2
3
4
>>> print(index(l, 'quux'))
None
>>> print(index(l, 'bar'))
1

这样做的缺点是,您可能会检查返回值isis not是否为None:

1
2
3
result = index(a_list, value)
if result is not None:
    do_something(result)

>列表中的多个值

如果你可以有更多的发生,你不会得到完整的信息与list.index:

1
2
3
4
5
>>> l.append('bar')
>>> l
['foo', 'bar', 'baz', 'bar']
>>> l.index('bar')              # nothing at index 3?
1

你可以列举出一个列表来理解索引:

1
2
3
4
>>> [index for index, v in enumerate(l) if v == 'bar']
[1, 3]
>>> [index for index, v in enumerate(l) if v == 'boink']
[]

如果你没有发生,你可以检查布尔检查的结果,或只是做什么,如果你循环的结果:

1
2
3
indexes = [index for index, v in enumerate(l) if v == 'boink']
for index in indexes:
    do_something(index)

与熊猫更好地咀嚼数据

如果你有熊猫,你可以很容易地得到这个信息与一系列对象:

1
2
3
4
5
6
7
8
>>> import pandas as pd
>>> series = pd.Series(l)
>>> series
0    foo
1    bar
2    baz
3    bar
dtype: object

比较检查将返回一系列布尔值:

1
2
3
4
5
6
>>> series == 'bar'
0    False
1     True
2    False
3     True
dtype: bool

通过下标符号将布尔级数传递给级数,就得到了匹配的成员:

1
2
3
4
>>> series[series == 'bar']
1    bar
3    bar
dtype: object

如果只需要索引,index属性返回一系列整数:

1
2
>>> series[series == 'bar'].index
Int64Index([1, 3], dtype='int64')

如果你想在列表或元组中使用它们,只需将它们传递给构造函数:

1
2
>>> list(series[series == 'bar'].index)
[1, 3]

是的,你也可以使用列表理解和enumerate,但在我看来,这并不优雅——你在用Python做平等测试,而不是让用C编写的内置代码来处理它:

1
2
>>> [i for i, value in enumerate(l) if value == 'bar']
[1, 3]

这是XY问题吗?

The XY problem is asking about your attempted solution rather than your actual problem.

为什么需要列表中给定元素的索引?

如果您已经知道了值,为什么还要关心它在列表中的位置呢?

如果没有这个值,那么捕获ValueError将非常冗长—我宁愿避免这样做。

我通常会遍历列表,所以我通常会保留一个指向任何有趣信息的指针,使用enumerate获得索引。

如果您正在咀嚼数据,您可能应该使用panda——它拥有比我所展示的纯Python工作区更优雅的工具。

我不记得我自己需要什么。不过,我已经浏览了Python标准库,并看到了它的一些优秀用途。

它在idlelib中有许多用途,用于GUI和文本解析。

keyword模块使用它在模块中查找注释标记,从而通过元编程自动生成其中的关键字列表。

在Lib/mail .py中,它看起来像一个有序映射:

1
key_list[key_list.index(old)] = new

1
del key_list[key_list.index(key)]

在Lib / http / cookiejar。py,似乎是用来得到下个月的:

1
mon = MONTHS_LOWER.index(mon.lower())+1

在Lib/tar文件.py类似于distutils,以获得一个切片到一个项目:

1
members = members[:members.index(tarinfo)]

在Lib / pickletools.py:

1
numtopop = before.index(markobject)

这些用法的共同之处在于,它们似乎对受限制的大小列表进行操作(这很重要,因为O(n)查找list.index的时间很长),而且它们主要用于解析(在空闲的情况下,还用于UI)。

虽然有它的用例,但它们相当少见。如果您发现自己正在寻找这个答案,请问问自己,您所做的是否最直接地使用了该语言为您的用例提供的工具。


所有带有zip函数的索引:

1
2
3
4
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等于您要查找的内容时,它是列表的索引。

1
2
3
4
5
>>> alist = ['foo', 'spam', 'egg', 'foo']
>>> foo_indexes = [n for n,x in enumerate(alist) if x=='foo']
>>> foo_indexes
[0, 3]
>>>

让我们的函数findindex

这个函数接受item和list作为参数,并返回list中item的位置,就像我们之前看到的那样。

1
2
3
4
5
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
[1, 3, 5, 7]

简单

1
2
3
for n, i in enumerate([1, 2, 3, 4, 1]):
    if i == 1:
        print(n)

输出:

1
2
0
4


你只要跟着就行了

1
2
3
4
a = [['hand', 'head'], ['phone', 'wallet'], ['lost', 'stock']]
b = ['phone', 'lost']

res = [[x[0] for x in a].index(y) for y in b]


另一个选择

1
2
3
4
5
6
7
8
9
10
11
>>> a = ['red', 'blue', 'green', 'red']
>>> b = 'red'
>>> offset = 0;
>>> indices = list()
>>> for i in range(a.count(b)):
...     indices.append(a.index(b,offset))
...     offset = indices[-1]+1
...
>>> indices
[0, 3]
>>>


,现在,对于一些完全不同的…

…比如在获取索引之前确认项目的存在。这种方法的好处是,函数总是返回一个索引列表——即使它是一个空列表。它也适用于字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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窗口时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()函数。

是这样的:

1
2
3
4
5
6
7
8
9
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窗口时,会产生:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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在他之前的答案中所建议的。在我最初回答这个问题的时候,我甚至没有看到那个答案,因为我不理解它。我希望我稍微详细的例子将有助于理解。

如果上面的一行代码对您来说仍然没有意义,我强烈建议您理解谷歌"python列表",并花几分钟熟悉一下。它只是众多功能强大的特性之一,这些特性使使用Python开发代码成为一种乐趣。


来自FMc和user7177的答案的一个变体将给出一个dict,它可以返回任何条目的所有索引:

1
2
3
4
5
6
7
8
9
>>> 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的次数,但并不能保证效率。


这个解决方案不像其他的那么强大,但是如果你是一个初学者,只知道for循环,仍然可以找到一个项目的第一个索引,同时避免ValueError:

1
2
3
4
5
6
7
8
def find_element(p,t):
    i = 0
    for e in p:
        if e == t:
            return i
        else:
            i +=1
    return -1


由于Python列表是从零开始的,我们可以使用zip内置函数如下:

1
>>> [i for i,j in zip(range(len(haystack)), haystack) if j == 'needle' ]

其中"haystack"是有问题的列表,"needle"是要查找的条目。

(注意:这里我们使用i来迭代获得索引,但是如果我们需要更关注项目,我们可以切换到j。)


1
2
3
4
5
6
7
8
9
10
11
name ="bar"
list = [["foo", 1], ["bar", 2], ["baz", 3]]
new_list=[]
for item in list:
    new_list.append(item[0])
print(new_list)
try:
    location= new_list.index(name)
except:
    location=-1
print (location)

这说明如果字符串不在列表中,如果不在列表中,那么location = -1


如果没有找到项目,Python index()方法将抛出一个错误,这很糟糕!

因此,你可以让它类似于JavaScript的indexOf()函数,如果没有找到该项目返回-1:

1
2
3
4
    try:
        index = array.index('search_keyword')
    except ValueError:
        index = -1

对此有一个更实用的答案。

1
list(filter(lambda x: x[1]=="bar",enumerate(["foo","bar","baz","bar","baz","bar","a","b","c"])))

更一般的形式:

1
2
3
def get_index_of(lst, element):
    return list(map(lambda x: x[0],\
       (list(filter(lambda x: x[1]==element, enumerate(lst))))))


查找列表L中项目x的索引:

1
idx = L.index(x) if (x in L) else -1


There is two possibility if the list has no repeated items that you need to check the index for

1
2
 eg: li=[10,20,30] # here need to get index of 20 means
     li.index(20) # will work properly because 20 is not repeated

如果它的重复意味着它只会给出第一个索引

如果您需要获得项目所在的所有索引,这意味着

1
eg: li=[10,20,30,20,40, 50, 10] # here need to get index of 20 means its have 2 index (1,3)

要得到它,你需要像这样做

1
2
 li=[10,20,30,20,40, 50, 10]
 [i for i, e in enumerate(li) if e == 20]

然后您将得到一个索引列表,如o/p [1,3]


让我们将名称lst赋予您拥有的列表。可以将列表lst转换为numpy array。然后使用numpy。从何处获取列表中所选项的索引。下面是实现它的方法。

1
2
3
4
5
6
import numpy as np

lst = ["foo","bar","baz"]  #lst: : 'list' data type
print np.where( np.array(lst) == 'bar')[0][0]

>>> 1

对于像我这样来自另一种语言的人来说,也许用一个简单的循环就能更容易理解和使用它:

1
2
3
4
5
mylist = ["foo","bar","baz","bar"]
newlist = enumerate(mylist)
for index, item in newlist:
  if item =="bar":
    print(index, item)

我很感激枚举到底做了什么?这帮助我理解。


如果性能值得关注:

在众多的答案中提到,list.index(item)方法的内置方法是O(n)算法。如果您需要执行此操作一次,也可以。但是,如果需要多次访问元素的索引,那么更有意义的做法是首先创建一个条目索引对的字典(O(n)),然后每次需要时都在O(1)处访问索引。

如果你确定你的清单上的项目不会重复,你可以很容易:

1
2
3
4
5
6
7
8
myList = ["foo","bar","baz"]

# Create the dictionary
myDict = dict((e,i) for i,e in enumerate(myList))

# Lookup
myDict["bar"] # Returns 1
# myDict.get("blah") if you don't want an error to be raised if element not found.

如果你可能有重复的元素,并需要返回所有的索引:

1
2
3
4
5
6
7
8
9
10
from collections import defaultdict as dd
myList = ["foo","bar","bar","baz","foo"]

# Create the dictionary
myDict = dd(list)
for i,e in enumerate(myList):
    myDict[e].append(i)

# Lookup
myDict["foo"] # Returns [0, 4]

正如@TerryA所指出的,许多答案讨论了如何找到一个索引。

more_itertools是一个第三方库,用于在一个迭代器中定位多个索引。

鉴于

1
2
3
4
import more_itertools as mit


iterable = ["foo","bar","baz","ham","foo","bar","baz"]

代码

查找多个观测指标:

1
2
list(mit.locate(iterable, lambda x: x =="bar"))
# [1, 5]

测试多个项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
list(mit.locate(iterable, lambda x: x in {"bar","ham
<hr><p>使用dictionary,首先处理列表,然后将索引添加到其中</P>[cc lang="
python"]from collections import defaultdict

index_dict = defaultdict(list)    
word_list =  ['foo','bar','baz','bar','any', 'foo', 'much']

for word_index in range(len(word_list)) :
    index_dict[word_list[word_index]].append(word_index)

word_index_to_find = 'foo'      
print(index_dict[word_index_to_find])

# output :  [0, 5]