Index()将给出列表中第一个出现的项。是否有一个巧妙的技巧可以返回一个元素列表中的所有索引?


当前回答

There’s an answer using np.where to find the indices of a single value, which is not faster than a list-comprehension, if the time to convert a list to an array is included The overhead of importing numpy and converting a list to a numpy.array probably makes using numpy a less efficient option for most circumstances. A careful timing analysis would be necessary. In cases where multiple functions/operations will need to be performed on the list, converting the list to an array, and then using numpy functions will likely be a faster option. This solution uses np.where and np.unique to find the indices of all unique elements in a list. Using np.where on an array (including the time to convert the list to an array) is slightly slower than a list-comprehension on a list, for finding all indices of all unique elements. This has been tested on an 2M element list with 4 unique values, and the size of the list/array and number of unique elements will have an impact. Other solutions using numpy on an array can be found in Get a list of all indices of repeated elements in a numpy array Tested in [python 3.10.4, numpy 1.23.1] and [python 3.11.0, numpy 1.23.4]

import numpy as np
import random  # to create test list

# create sample list
random.seed(365)
l = [random.choice(['s1', 's2', 's3', 's4']) for _ in range(20)]

# convert the list to an array for use with these numpy methods
a = np.array(l)

# create a dict of each unique entry and the associated indices
idx = {v: np.where(a == v)[0].tolist() for v in np.unique(a)}

# print(idx)
{'s1': [7, 9, 10, 11, 17],
 's2': [1, 3, 6, 8, 14, 18, 19],
 's3': [0, 2, 13, 16],
 's4': [4, 5, 12, 15]}

%timeit在2M元素列表中,有4个唯一的str元素

# create 2M element list
random.seed(365)
l = [random.choice(['s1', 's2', 's3', 's4']) for _ in range(2000000)]

功能

def test1():
    # np.where: convert list to array and find indices of a single element
    a = np.array(l)
    return np.where(a == 's1')
    

def test2():
    # list-comprehension: on list l and find indices of a single element
    return [i for i, x in enumerate(l) if x == "s1"]


def test3():
    # filter: on list l and find indices of a single element
    return list(filter(lambda i: l[i]=="s1", range(len(l))))


def test4():
    # use np.where and np.unique to find indices of all unique elements: convert list to array
    a = np.array(l)
    return {v: np.where(a == v)[0].tolist() for v in np.unique(a)}


def test5():
    # list comprehension inside dict comprehension: on list l and find indices of all unique elements
    return {req_word: [idx for idx, word in enumerate(l) if word == req_word] for req_word in set(l)}

函数调用

%timeit test1()
%timeit test2()
%timeit test3()
%timeit test4()
%timeit test5()

python 3.10.4

214 ms ± 19.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
85.1 ms ± 1.48 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
146 ms ± 1.65 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
365 ms ± 11.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
360 ms ± 5.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

结果python 3.11.0

209 ms ± 15.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
70.4 ms ± 1.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
132 ms ± 4.65 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
371 ms ± 20.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
314 ms ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

其他回答

你可以使用枚举的列表推导式:

indices = [i for i, x in enumerate(my_list) if x == "whatever"]

迭代器enumerate(my_list)为列表中的每一项生成对(index, item)。使用i, x作为循环变量目标,将这些对解包到索引i和列表项x中。我们向下筛选到所有符合条件的x,并选择这些元素的索引i。

虽然不是列表的直接解决方案,但numpy真的很适合这类事情:

import numpy as np
values = np.array([1,2,3,1,2,4,5,6,3,2,1])
searchval = 3
ii = np.where(values == searchval)[0]

返回:

ii ==>array([2, 8])

对于包含大量元素的列表(数组),这比其他解决方案要快得多。

如果你使用的是Python 2,你可以用这个实现相同的功能:

f = lambda my_list, value:filter(lambda x: my_list[x] == value, range(len(my_list)))

其中my_list是要获取索引的列表,value是要搜索的值。用法:

f(some_list, some_element)

使用list.index的解决方案:

def indices(lst, element):
    result = []
    offset = -1
    while True:
        try:
            offset = lst.index(element, offset+1)
        except ValueError:
            return result
        result.append(offset)

对于大型列表,它比使用enumerate的列表理解要快得多。如果已经有数组,它也比numpy解决方案慢得多,否则转换的成本超过了速度增益(在包含100、1000和10000个元素的整数列表上进行测试)。

注意:根据Chris_Rands的评论,需要注意的是:如果结果足够稀疏,这个解决方案比列表推导式更快,但是如果列表中有很多正在搜索的元素的实例(超过列表的15%,在一个包含1000个整数的列表测试中),列表推导式更快。

获取列表中一个或多个(相同的)项的所有出现情况和位置

使用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]
>>>

让我们把函数命名为findindex

这个函数以项目和列表作为参数,并返回项目在列表中的位置,就像我们前面看到的那样。

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