Home Finding the index of an item given a list containing it in Python
Reply: 21

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

Eugene M
1#
Eugene M Published in 2008-10-07 01:39:38Z

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?

David Heffernan
2#
David Heffernan Reply to 2015-10-28 15:40:26Z
>>> ["foo", "bar", "baz"].index("bar")
1

Reference: Data Structures > More on Lists

davidavr
3#
davidavr Reply to 2008-10-07 13:19:56Z

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.

HongboZhu
4#
HongboZhu Reply to 2012-03-09 10:38:09Z

index() returns the first index of value!

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

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"])
savinson
5#
savinson Reply to 2017-10-31 07:45:46Z
a = ["foo","bar","baz",'bar','any','much']

indexes = [index for index in range(len(a)) if a[index] == 'bar']
tanzil
6#
tanzil Reply to 2017-04-24 10:00:10Z

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
KeyWeeUsr
7#
KeyWeeUsr Reply to 2016-12-24 14:24:33Z

All of the proposed functions here reproduce inherent language behavior but obscure what's going on.

[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

Why write a function with exception handling if the language provides the methods to do what you want itself?

octoback
8#
octoback Reply to 2013-05-29 07:17:15Z

Simply you can go with

a = [['hand', 'head'], ['phone', 'wallet'], ['lost', 'stock']]
b = ['phone', 'lost']

res = [[x[0] for x in a].index(y) for y in b]
Mathitis2Software
9#
Mathitis2Software Reply to 2013-05-29 19:17:21Z

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]
>>> 
TerryA
10#
TerryA Reply to 2017-11-01 23:55:58Z

The majority of answers explain how to find a single index, but their methods do not return multiple indexes if the item is in the list multiple times. Use enumerate():

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

The index() function only returns the first occurrence, while enumerate() returns all occurrences.

As a list comprehension:

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

Here's also another small solution with itertools.count() (which is pretty much the same approach as enumerate):

from itertools import izip as zip, count # izip for maximum efficiency
[i for i, j in zip(count(), ['foo', 'bar', 'baz']) if j == 'bar']

This is more efficient for larger lists than using 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
FMc
11#
FMc Reply to 2017-12-23 16:43:48Z

To get all indexes:

 indexes = [i for i,x in enumerate(xs) if x == 'foo']
bvanlew
12#
bvanlew Reply to 2014-03-28 09:11:57Z

A variant on the answer from FMc and user7177 will give a dict that can return all indices for any entry:

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

You could also use this as a one liner to get all indices for a single entry. There are no guarantees for efficiency, though I did use set(a) to reduce the number of times the lambda is called.

user3670684
13#
user3670684 Reply to 2014-05-26 04:26:52Z

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
MrWonderful
14#
MrWonderful Reply to 2017-07-28 21:30:30Z

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]
>>> 
totallyhuman
15#
totallyhuman Reply to 2017-11-12 06:07:52Z

This solution is not as powerful as others, but if you're a beginner and only know about forloops it's still possible to find the first index of an item while avoiding the ValueError:

def find_element(p,t):
    i = 0
    for e in p:
        if e == t:
            return i
        else:
            i +=1
    return -1
Coder123
16#
Coder123 Reply to 2015-07-05 13:12:19Z
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)

This accounts for if the string is not in the list too, if it isn't in the list then location = -1

Arnaldo P. Figueira Figueira
17#
Arnaldo P. Figueira Figueira Reply to 2015-11-11 05:16:38Z

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')
rbrisuda
18#
rbrisuda Reply to 2015-11-17 19:05:23Z

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.

Giovanni Gianni
19#
Giovanni Gianni Reply to 2018-01-26 17:20:01Z

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

We use a list telling us each position of 'foo', instead of the index() method, because this one tells us the first occurence of 'foo' and not all the position in the list. So, if we got more than one occurrence of 'foo', we ca use this list comprehention, to memorize all of them. The list comprehension checks every item, compares it with the string 'foo' and - if it is true - it stores the position in the new list foo_indexes. At the end of the cycle, the list will have all the indexes stored to be used lately for your purposes in the code.

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

Let's make our Function findindex

A nice way to make this code usable and easy to adopt in different project is this. Create a function and then put it somewhere, so that you could import it at need, without worrying anymore about the code.

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]

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

output


[1, 3, 5, 7]
jihed gasmi
20#
jihed gasmi Reply to 2017-08-12 20:19:26Z

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)

Aaron Hall
21#
Aaron Hall Reply to 2017-09-02 23:56:20Z

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?

Well, sure, there's the index method, which returns the index of the first occurrence:

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

There are a couple of issues with this method:

  • if the value isn't in the list, you'll get a ValueError
  • if more than one of the value is in the list, you only get the index for the first one

No values

If the value could be missing, you need to catch the ValueError.

You can do so with a reusable definition like this:

def index(a_list, value):
    try:
        return a_list.index(value)
    except ValueError:
        return None

And use it like this:

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

And the downside of this is that you will probably have a check for if the returned value is or is not None:

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

More than one value in the list

If you could have more occurrences, you'll not get complete information with list.index:

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

You might enumerate into a list comprehension the indexes:

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

If you have no occurrences, you can check for that with boolean check of the result, or just do nothing if you loop over the results:

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

Better data munging with pandas

If you have pandas, you can easily get this information with a Series object:

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

A comparison check will return a series of booleans:

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

Pass that series of booleans to the series via subscript notation, and you get just the matching members:

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

If you want just the indexes, the index attribute returns a series of integers:

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

And if you want them in a list or tuple, just pass them to the constructor:

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

Yes, you could use a list comprehension with enumerate too, but that's just not as elegant, in my opinion - you're doing tests for equality in Python, instead of letting builtin code written in C handle it:

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

Is this an XY problem?

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

Why do you think you need the index given an element in a list?

If you already know the value, why do you care where it is in a list?

If the value isn't there, catching the ValueError is rather verbose - and I prefer to avoid that.

I'm usually iterating over the list anyways, so I'll usually keep a pointer to any interesting information, getting the index with enumerate.

If you're munging data, you should probably be using pandas - which has far more elegant tools than the pure Python workarounds I've shown.

I do not recall needing list.index, myself. However, I have looked through the Python standard library, and I see some excellent uses for it.

There are many, many uses for it in idlelib, for GUI and text parsing.

The keyword module uses it to find comment markers in the module to automatically regenerate the list of keywords in it via metaprogramming.

In Lib/mailbox.py it seems to be using it like an ordered mapping:

key_list[key_list.index(old)] = new

and

del key_list[key_list.index(key)]

In Lib/http/cookiejar.py, seems to be used to get the next month:

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

In Lib/tarfile.py similar to distutils to get a slice up to an item:

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

In Lib/pickletools.py:

numtopop = before.index(markobject)

What these usages seem to have in common is that they seem to operate on lists of constrained sizes (important because of O(n) lookup time for list.index), and they're mostly used in parsing (and UI in the case of Idle).

While there are use-cases for it, they are fairly uncommon. If you find yourself looking for this answer, ask yourself if what you're doing is the most direct usage of the tools provided by the language for your use-case.

mpoletto
22#
mpoletto Reply to 2018-01-30 21:32:06Z

For those caming from another language like me, maybe with a simple loop it's easier to understand and use it:

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

Thankfull for https://www.codecademy.com/en/forum_questions/5087f2d786a27b02000041a9, that helped me to understand.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.256603 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO