9

If one was to attempt to find the indexes of an item in a list you could do it a couple different ways here is what I know to be the fastest:

aList = [123, 'xyz', 'zara','xyz', 'abc']; 
indices = [i for i, x in enumerate(aList) if x == "xyz"]
print(indices)

Another way not pythonic and slower:

count = 0
indices = []
aList = [123, 'xyz', 'zara','xyz', 'abc'];
for i in range(0,len(aList):
    if 'xyz' == aList[i]:
        indices.append(i)
print(indices)

The first method is undoubtedly faster however what if you wanted to go faster, is there a way? For the first index using method:

aList = [123, 'xyz', 'zara','xyz', 'abc'];             
print "Index for xyz : ", aList.index( 'xyz' ) 

is very fast but can't handle multiple indexes.
How might one go about speeding things up?

martineau
  • 119,623
  • 25
  • 170
  • 301
Tyler Cowan
  • 820
  • 4
  • 13
  • 35

6 Answers6

11

Use list.index(elem, start)! That uses a for loop in C (see its implementation list_index_impl function in the source of CPython's listobject.c). Avoid looping through all the elements in Python, it is slower than in C.

def index_finder(lst, item):
    """A generator function, if you might not need all the indices"""
    start = 0
    while True:
        try:
            start = lst.index(item, start)
            yield start
            start += 1
        except ValueError:
            break

import array
def index_find_all(lst, item, results=None):
    """ If you want all the indices.
    Pass results=[] if you explicitly need a list,
    or anything that can .append(..)
    """
    if results is None:
        length = len(lst)
        results = (array.array('B') if length <= 2**8 else
                   array.array('H') if length <= 2**16 else
                   array.array('L') if length <= 2**32 else
                   array.array('Q'))
    start = 0
    while True:
        try:
            start = lst.index(item, start)
            results.append(start)
            start += 1
        except ValueError:
            return results

# Usage example
l = [1, 2, 3, 4, 5, 6, 7, 8] * 32

print(*index_finder(l, 1))
print(*index_find_all(l, 1))
martineau
  • 119,623
  • 25
  • 170
  • 301
poke53280
  • 456
  • 5
  • 5
9
def find(target, myList):
    for i in range(len(myList)):
        if myList[i] == target:
            yield i

def find_with_list(myList, target):
     inds = []
     for i in range(len(myList)):
         if myList[i] == target:
             inds += i,
     return inds


In [8]: x = range(50)*200
In [9]: %timeit [i for i,j in enumerate(x) if j == 3]
1000 loops, best of 3: 598 us per loop

In [10]: %timeit list(find(3,x))
1000 loops, best of 3: 607 us per loop
In [11]: %timeit find(3,x)
1000000 loops, best of 3: 375 ns per loop

In [55]: %timeit find_with_list(x,3)
1000 loops, best of 3: 618 us per loop

Assuming you want a list as your output:

  • All options seemed exhibit similar time performance for my test with the list comprehension being the fastest (barely).

If using a generator is acceptable, it's way faster than the other approaches. Though it doesn't account for actually iterating over the indices, nor does it store them, so the indices cannot be iterated over a second time.

martineau
  • 119,623
  • 25
  • 170
  • 301
Garrett R
  • 2,687
  • 11
  • 15
  • so what your saying is iterating over each index and doing a direct comparison is the fastest way to get all index locations of matching items in a list? – Tyler Cowan Feb 26 '16 at 01:50
  • it's the fastest way I know how assuming a serial computation. If it were a giant list and you could split it and process parts in parallel, that would likely be faster – Garrett R Feb 26 '16 at 01:51
  • 2
    `[i for i,j in enumerate(x) if x == 3]`, second `x` should be `j`. – gil Feb 26 '16 at 01:53
  • @GarrettR I was thinking parallel might be the way to go like divide and conquer Ill have to look into it. there has got to be a better way. – Tyler Cowan Feb 26 '16 at 01:56
  • @gill whoa! that was a huge mistake and makes a lot of sense why it was slow. I fixed the code and results. Thanks! – Garrett R Feb 26 '16 at 01:57
  • what am omcredob;e amswer – dipl0 Mar 10 '20 at 07:05
3

Simply create a dictionary of item->index from the list of items using zip like so:

items_as_dict = dict(zip(list_of_items,range(0,len(list_of_items))))
index = items_as_dict(item)
Ahmadov
  • 1,567
  • 5
  • 31
  • 48
1

To get the index of the item, you can use the dictionary.

aList = [123, 'xyz', 'zara','xyz', 'abc'];
#The following apporach works only on lists with unique values
aList = list(np.unique(aList)); 
dict = enumerate(aList);
# get inverse mapping of above dictionary, replace key with values
inv_dict = dict(zip(dict.values(),dict.keys()))
# to get index of item by value, use 'inv_dict' and to get value by index, use 'dict'
valueofItemAtIndex0 = dict[0]; # value = 123
indexofItemWithValue123 = inv_dict[123]; # index = 0
Harish Mashetty
  • 433
  • 3
  • 13
0
D=dict()
for i, item in enumerate(l):
    if item not in D:
        D[item] = [i]
    else:
        D[item].append(i)

Then simply call D[item] to get the indices that match. You'll give up initial calculation time but gain it during call time.

John
  • 633
  • 6
  • 10
0

I used another way to find the index of a element in a list in Python 3:

def index_of(elem, a):
    a_e = enumerate(a)
    a_f = list(filter(lambda x: x[1] == elem, a_e))
    if a_f:
        return a_f[0][0]
    else:
        return -1

Some tests:

a=[1,2,3,4,2]
index_of(2,a)

This function always return the first occurrence of the element. If element ins't in the list, return -1. For my goals, that solution worked well.

Ângelo Polotto
  • 8,463
  • 2
  • 36
  • 37