Eugene M
Eugene M

Reputation: 49035

How to find the index for a given item in a list?

Given a list ["foo", "bar", "baz"] and an item in the list "bar", how do I get its index 1?

Upvotes: 4463

Views: 6612315

Answers (30)

amrita yadav
amrita yadav

Reputation: 161

Here are different methods to find all occurrences of "bar" in a list, I have ranked by execution speed and usecase:

lst = ["foo", "bar", "baz"]
item = "bar"

itertools.compress (Fastest: ~0.026s) Memory Efficient

from itertools import compress
indices = list(compress(range(len(lst)), [val == item for val in lst]))

List Comprehension (~0.018s) readability & simplicity

indices = [i for i, v in enumerate(lst) if v == item]

collections.deque (~0.053s) Faster Append

from collections import deque
indices = deque()
for i, val in enumerate(lst):
    if val == item:
        indices.append(i)
indices = list(indices)

filter + lambda (~0.029s) Functional Approach

indices = list(filter(lambda i: lst[i] == item, range(len(lst))))

NumPy (np.where) (~0.165s) Faster for Large Lists

import numpy as np
indices = np.where(np.array(lst) == item)[0].tolist()

Pandas (pd.Series.index) (~9.475s) Best for DataFrames & Large Datasets

import pandas as pd
indices = pd.Series(lst).index[pd.Series(lst) == item].tolist()

Output:

[1]

Upvotes: 0

MrWonderful
MrWonderful

Reputation: 2578

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

One can certainly use the above code; however, the much more idiomatic way to get the same behavior would be to use list comprehension, along with the enumerate() function.

Something like this:

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

Which, when pasted into an interactive Python window yields:

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

(This is exactly what FMc suggested in his earlier answer. I hope that my somewhat more verbose example will aid understanding.)

If the single line of code above still doesn't make sense to you, I highly recommend you research list comprehensions and take a few minutes to familiarize yourself. It's just one of the many powerful features that make it a joy to use Python to develop code.

Upvotes: 23

Badri Paudel
Badri Paudel

Reputation: 1630

There is a chance that that value may not be present so to avoid this ValueError, we can check if that actually exists in the list .

list =  ["foo", "bar", "baz"]

item_to_find = "foo"

if item_to_find in list:
    index = list.index(item_to_find)
    print("Index of the item is " + str(index))
else:
    print("That word does not exist") 

Expected output of above code: Index of the item is 0

A more efficient alternative way:

Since calling item_to_find in list and list.index(item_to_find) is doing two searches, it can be shortened with only one operation using try, except. Since it throws ValueError when the item is not in the list, we can use that message to print for user information to indicate what went wrong.

Following code can be used as an enhancement.

list =  ["foo", "bar", "baz"]
item_to_find = "fooz"

try:
    index = list.index(item_to_find)
    print("Index of the item is " + str(index))

except ValueError as error:
    print(f'Item couldn\'t be found because {error}.')

Expected output of the above code is: Item couldn't be found because 'fooz' is not in list

Upvotes: 13

Alejadro Xalabarder
Alejadro Xalabarder

Reputation: 1630

A function "indexof" similar to another languages that returs -1 if the element is not found can be written like

def indexof (obj, elem, offset=0):
    if elem in obj[offset:]:
        return offset + obj[offset:].index(elem)
    return -1


obj = ["foo", "bar", "baz", "foo"]

print (indexof(obj, "not here"))
print (indexof(obj, "baz"))
print (indexof(obj, "foo", 1))

which returns

-1
2
3

or an optimized version for big lists

def indexof (obj, elem, offset=0):
    if offset == 0:
       # no need of a sublist
       if elem in obj:
          return obj.index(elem)
       return -1

    sublist = obj[offset:]
    if elem in sublist:
        return offset + sublist.index(elem)
    return -1

Upvotes: 1

Hamed Baatour
Hamed Baatour

Reputation: 6942

Python index() method throws an error if the item was not found. So instead you can make it similar to the indexOf() function of JavaScript which returns -1 if the item was not found:

def indexof( array, elem):
try:
    return array.index(elem)
except ValueError:
    return -1

Upvotes: 15

Hadi Mir
Hadi Mir

Reputation: 5133

One of the simplest ways to find the index of an element in a list is to do as follows

arr = ["foo", "bar", "baz"] 
el = "bar"
try:
  index = arr.index(el)
  return index
except:
  return 'element not found'

Upvotes: 1

mirapole
mirapole

Reputation: 1011

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

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

I am thankful for So what exactly does enumerate do?. That helped me to understand.

Upvotes: 4

ggorlen
ggorlen

Reputation: 57195

Amazingly, next's fallback value second parameter mentioned in this comment in a duplicate thread hasn't been shown here yet.

The basic .index() works well when you can compare whole objects, but it's common to need to search a list of objects or dicts for a particular item by a certain property, in which case a generator with a condition is the natural choice:

>>> users = [{"id": 2, "name": "foo"}, {"id": 3, "name": "bar"}]
>>> target_id = 2
>>> found_user = next(x for x in users if x["id"] == target_id)
>>> found_user
{'id': 2, 'name': 'foo'}

This stops at the first matching element and is reasonably succinct.

However, if no matching element is found, a StopIteration error is raised, which is a little awkward to deal with. Luckily, next offers a second parameter next(gen, default) fallback to provide a more natural, except-free control flow:

>>> found_user = next((x for x in users if x["id"] == target_id), None)
>>> if not found_user:
...     print("user not found")
... 
user not found

This is a bit more verbose, but still fairly readable.

If an index is desired:

>>> found_idx = next((i for i, x in enumerate(users) if x["id"] == 1), None)
>>> found_idx
None
>>> next((i for i, x in enumerate(users) if x["id"] == 3), None)
1

As this comment points out, it may be best not to return the typical -1 for a missing index, since that's a valid index in Python. Raising is appropriate if None seems odd to return.

These are a bit verbose, but feel free to bury the code in a helper function if you're using it repeatedly, providing an arbitrary predicate.

>>> def find(it, pred):
...     return next((x for x in it if pred(x)), None)
...
>>> find(users, lambda user: user["id"] == 2)
{'id': 2, 'name': 'foo'}
>>> print(find(users, lambda user: user["id"] == 42))
None
>>> find("foobAr", str.isupper) # works on any iterable!
'A'

Upvotes: 3

Sanu
Sanu

Reputation: 123

A simple solution in python:

li1=["foo","bar","baz"]
for i in range(len(li1)):
     if li1[i]=="bar":
          print(i)

The data type of the list elements is irrelevant. Just replace the "bar" with the element you are looking for. We can also write a function for this as:

def indexfinder(element,lis):
    for i in range(len(lis)):
        if lis[i]==element:
            return i

Upvotes: 0

Alex Coventry
Alex Coventry

Reputation: 70957

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

See the documentation for the built-in .index() method of the list:

list.index(x[, start[, end]])

Return zero-based index in the list of the first item whose value is equal to x. Raises a ValueError if there is no such item.

The optional arguments start and end are interpreted as in the slice notation and are used to limit the search to a particular subsequence of the list. The returned index is computed relative to the beginning of the full sequence rather than the start argument.

Caveats

Linear time-complexity in list length

An index call checks every element of the list in order, until it finds a match. If the list is long, and if there is no guarantee that the value will be near the beginning, this can slow down the code.

This problem can only be completely avoided by using a different data structure. However, if the element is known to be within a certain part of the list, the start and end parameters can be used to narrow the search.

For example:

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

The second call is orders of magnitude faster, because it only has to search through 10 elements, rather than all 1 million.

Only the index of the first match is returned

A call to index searches through the list in order until it finds a match, and stops there. If there could be more than one occurrence of the value, and all indices are needed, index cannot solve the problem:

>>> [1, 1].index(1) # the `1` index is not found.
0

Instead, use a list comprehension or generator expression to do the search, with enumerate to get indices:

>>> # A list comprehension gives a list of indices directly:
>>> [i for i, e in enumerate([1, 2, 1]) if e == 1]
[0, 2]
>>> # A generator comprehension gives us an iterable object...
>>> g = (i for i, e in enumerate([1, 2, 1]) if e == 1)
>>> # which can be used in a `for` loop, or manually iterated with `next`:
>>> next(g)
0
>>> next(g)
2

The list comprehension and generator expression techniques still work if there is only one match, and are more generalizable.

Raises an exception if there is no match

As noted in the documentation above, using .index will raise an exception if the searched-for value is not in the list:

>>> [1, 1].index(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 2 is not in list

If this is a concern, either explicitly check first using item in my_list, or handle the exception with try/except as appropriate.

The explicit check is simple and readable, but it must iterate the list a second time. See What is the EAFP principle in Python? for more guidance on this choice.

Upvotes: 6078

LunaticXXD10
LunaticXXD10

Reputation: 427

Here's a two-liner using Python's index() function:

LIST = ['foo' ,'boo', 'shoo']
print(LIST.index('boo'))

Output: 1

Upvotes: 20

saolof
saolof

Reputation: 1661

Don't. If you absolutely need to, use the .index(item...) method on list. However, it takes linear time, and if you find yourself reaching for it, you are probably misusing lists to do something you should not do with them.

Most likely, you care either about 1) a two-way mapping between integers and items, or 2) about finding an item in a sorted list of items.

For the first one, use a pair of dictionaries. If you want a library that does this for you, use the bidict library.

For the second one, use methods that can properly make use of the fact that the list is sorted. Use the built-in bisect module in python.

If you find yourself wanting to insert items in a sorted list, you should also not use a sorted list. Either weaken the sorted requirement to a heap using the builtin heapq module, or use the sortedcontainers library.

It is bad practice to use a data structure that is not designed for what you want to do. Using one that matches the task you give it will both telegraph to the reader that you want to do that specific thing, and also make your solution a lot faster/more scalable in practice.

Upvotes: 0

FMc
FMc

Reputation: 42421

To get all indexes:

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

Upvotes: 246

My Car
My Car

Reputation: 4576

Try the following code:

["foo", "bar", "baz"].index("bar")

Refer to: https://www.programiz.com/python-programming/methods/list/index

Upvotes: 4

Deepeshkumar
Deepeshkumar

Reputation: 443

One can use zip() function to get the index of the value in the list. The code could be;

list1 = ["foo","bar","baz"]
for index,value in zip(range(0,len(list1)),list1):
    if value == "bar":
        print(index)

Upvotes: 0

Babatunde Mustapha
Babatunde Mustapha

Reputation: 2663

me = ["foo", "bar", "baz"]
me.index("bar") 

You can apply this for any member of the list to get their index

Upvotes: 37

Kofi
Kofi

Reputation: 1314

List comprehension would be the best option to acquire a compact implementation in finding the index of an item in a list.

a_list = ["a", "b", "a"]
print([index for (index , item) in enumerate(a_list) if item == "a"])

Upvotes: 12

sargupta
sargupta

Reputation: 1043

text = ["foo", "bar", "baz"]
target = "bar"

[index for index, value in enumerate(text) if value == target]

For a small list of elements, this would work fine. However, if the list contains a large number of elements, better to apply binary search with O(log n) runtime complexity .

Upvotes: 4

Franz Gastring
Franz Gastring

Reputation: 1130

Certain structures in python contains a index method that works beautifully to solve this question.

'oi tchau'.index('oi')     # 0
['oi','tchau'].index('oi') # 0
('oi','tchau').index('oi') # 0

References:

In lists

In tuples

In string

Upvotes: 2

user459872
user459872

Reputation: 24827

Pythonic way would to use enumerate but you can also use indexOf from operator module. Please note that this will raise ValueError if b not in a.

>>> from operator import indexOf
>>>
>>>
>>> help(indexOf)
Help on built-in function indexOf in module _operator:

indexOf(a, b, /)
    Return the first index of b in a.

>>>
>>>
>>> indexOf(("foo", "bar", "baz"), "bar") # with tuple
1
>>> indexOf(["foo", "bar", "baz"], "bar") # with list
1

Upvotes: 1

MD SHAYON
MD SHAYON

Reputation: 8063

I find this two solution is better and I tried it by myself

>>> expences = [2200, 2350, 2600, 2130, 2190]
>>> 2000 in expences
False
>>> expences.index(2200)
0
>>> expences.index(2350)
1
>>> index = expences.index(2350)
>>> expences[index]
2350

>>> try:
...     print(expences.index(2100))
... except ValueError as e:
...     print(e)
... 
2100 is not in list
>>> 


Upvotes: 5

illuminato
illuminato

Reputation: 1257

Simple option:

a = ["foo", "bar", "baz"]
[i for i in range(len(a)) if a[i].find("bar") != -1]

Upvotes: 0

Blackjack
Blackjack

Reputation: 1112

It just uses the python function array.index() and with a simple Try / Except it returns the position of the record if it is found in the list and return -1 if it is not found in the list (like on JavaScript with the function indexOf()).

fruits = ['apple', 'banana', 'cherry']

try:
  pos = fruits.index("mango")
except:
  pos = -1

In this case "mango" is not present in the list fruits so the pos variable is -1, if I had searched for "cherry" the pos variable would be 2.

Upvotes: 9

Caveman
Caveman

Reputation: 2953

For one comparable

# Throws ValueError if nothing is found
some_list = ['foo', 'bar', 'baz'].index('baz')
# some_list == 2

Custom predicate

some_list = [item1, item2, item3]

# Throws StopIteration if nothing is found
# *unless* you provide a second parameter to `next`
index_of_value_you_like = next(
    i for i, item in enumerate(some_list)
    if item.matches_your_criteria())

Finding index of all items by predicate

index_of_staff_members = [
    i for i, user in enumerate(users)
    if user.is_staff()]

Upvotes: 8

Vlad Bezden
Vlad Bezden

Reputation: 89735

If you are going to find an index once then using "index" method is fine. However, if you are going to search your data more than once then I recommend using bisect module. Keep in mind that using bisect module data must be sorted. So you sort data once and then you can use bisect. Using bisect module on my machine is about 20 times faster than using index method.

Here is an example of code using Python 3.8 and above syntax:

import bisect
from timeit import timeit

def bisect_search(container, value):
    return (
      index 
      if (index := bisect.bisect_left(container, value)) < len(container) 
      and container[index] == value else -1
    )

data = list(range(1000))
# value to search
value = 666

# times to test
ttt = 1000

t1 = timeit(lambda: data.index(value), number=ttt)
t2 = timeit(lambda: bisect_search(data, value), number=ttt)

print(f"{t1=:.4f}, {t2=:.4f}, diffs {t1/t2=:.2f}")

Output:

t1=0.0400, t2=0.0020, diffs t1/t2=19.60

Upvotes: 5

Coder123
Coder123

Reputation: 89

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

Upvotes: 7

TerryA
TerryA

Reputation: 60014

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

Upvotes: 722

sahasrara62
sahasrara62

Reputation: 11237

using dictionary , where process the list first and then add the index to it

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]

Upvotes: 1

Ketan
Ketan

Reputation: 1517

Finding index of item x in list L:

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

Upvotes: 16

Siddharth Satpathy
Siddharth Satpathy

Reputation: 3043

Let’s give the name lst to the list that you have. One can convert the list lst to a numpy array. And, then use numpy.where to get the index of the chosen item in the list. Following is the way in which you will implement it.

import numpy as np

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

>>> 1

Upvotes: 3

Related Questions