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


Answers

One thing that is really helpful in learning Python is to use the interactive help function:

>>> help(["foo", "bar", "baz"])
Help on list object:

class list(object)
 ...

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

which will often lead you to the method you are looking for.

Question

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?




all indexes with zip function

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')



Getting all the occurrences and the position of one or more (identical) items in a list

With enumerate(alist) you can store the first element (n) that is the index of the list when the element x is equal to what you look for.

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

Let's make our Function findindex

This function takes the item and the list as arg and return the position of the item in the liste, like we saw before.

def findindex(item2find,listOrString):
  "Search indexes of an item (arg.1) contained in a list or a string (arg.2)"
  return [n for n,item in enumerate(listOrString) if item==item2find]

indexes1 = findindex("1","010101010")
print(indexes1)

output


[1, 3, 5, 7]



A problem will arise if the element is not in the list. This function handles the issue:

# 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



Another option

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



To get all indexes:

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



And now, for something completely different...

... like confirming the existence of the item before getting the index. The nice thing about this approach is the function always returns a list of indices -- even if it is an empty list. It works with strings as well.

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')

When pasted into an interactive python window:

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



You have to set a condition to check if the element you're searching is in the list

if 'your_element' in mylist:
    print mylist.index('your_element')
else:
    print None



If you want all indexes, then you can use numpy:

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),)

It is clear, readable solution.




Since Python lists are zero-based,we can use the zip built-in function as follows :

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

where "haystack" is the list in question and "needle" is the item to look for.

(Note : Here we are iterating using i to get the indexes but if we need rather to focus on the items we can switch to j)




There is a more functional answer to this.

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

more generic form:

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