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

46

4391

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

Jannelle answered 7/10, 2008 at 1:39 Comment(5)
Are you returning: [1] The lowest index in case there are multiple instances of "bar", [2] All the indices of "bar"?Kandicekandinsky
a) Is it guaranteed that item is in the list, or else how we should handle the error case? (return None/ raise ValueError) b) Are list entries guaranteed to be unique, and should we return the first index of a match, or all indexes?Mulcahy
View the answers with numpy integration, numpy arrays are far more efficient than Python lists. If the list is short it's no problem making a copy of it from a Python list, if it isn't then perhaps you should consider storing the elements in numpy array in the first place.Property
I’m voting to close this question (in protest) because there are already 42 undeleted answers (and 16 more deleted) for a simple, one-liner reference question that almost all have the same built-in function at their core (as they should, because it's the only reasonable and sane approach to the problem and everything surrounding it is just error-checking or creatively re-interpreting the specification, which still only leaves one other reasonable, sane approach to the expanded problem).Dominate
There is no realistic chance of a better approach becoming possible in future versions of Python, because the existing approach is already just calling a single, built-in method on the list - as simple as it gets.Dominate
R
5978
>>> ["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.

Receiver answered 7/10, 2008 at 1:40 Comment(8)
index returns the first item whose value is "bar". If "bar" exists twice at list, you'll never find the key for the second "bar". See documentation: docs.python.org/3/tutorial/datastructures.htmlEscort
If you're only searching for one element (the first), I found that index() is just under 90% faster than list comprehension against lists of integers.Faires
What data structure should be used if the list is very long?Llanes
@izhang: Some auxillary index, like an {element -> list_index} dict, if the elements are hashable, and the position in the list matters.Receiver
sequence1 = sorted(sequence2, key=.sequence3.index) is a very handy idiom. You may use index more often if that's in your repertoire.Fisherman
that's true, @mpoletto... What can be done in that case of having multiple same values???Amanita
@jvel07, see the list/generator comprehension examples in my answer.Receiver
Raising an exception seems like a poor design choice in hindsight.Brentonbrentt
D
714

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
Damselfly answered 19/6, 2013 at 22:31 Comment(5)
Enumeration works better than the index-based methods for me, since I'm looking to gather the indices of strings using 'startswith" , and I need to gather multiple occurrences. Or is there a way to use index with "startswith" that I couldn't figure outQuintillion
In my hands, the enumerate version is consistently slightly faster. Some implementation details may have changed since the measurement above was posted.Receiver
This was already answered since '11: #6294679Legion
In Python 3 izip should be replaced by the built in zip. See hereTrenttrento
This is a good solution and it's much more flexible than the accepted solution. For example, if you only are expecting to have 1 value in the list, you can add a if statement to raise an exception if len([i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar']) > 1 otherwise you could just return [i for i, j in enumerate(['foo', 'bar', 'baz']) if j == 'bar'][0]Dobby
F
242

To get all indexes:

indexes = [i for i, x in enumerate(xs) if x == 'foo']
Fibroin answered 25/6, 2013 at 15:7 Comment(1)
There's already another question for this, added in '11: #6294679Legion
W
158

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"])
Whitehead answered 30/8, 2011 at 9:40 Comment(3)
And if doesn't exist in the list?Herpetology
Not-exist item will raise ValueErrorTrinitroglycerin
This answer would fit better here: #6294679Legion
D
110
a = ["foo","bar","baz",'bar','any','much']

indexes = [index for index in range(len(a)) if a[index] == 'bar']
Dichroite answered 21/8, 2012 at 12:1 Comment(0)
P
109

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
Premiere answered 16/4, 2013 at 10:19 Comment(0)
E
74

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
Entrance answered 26/5, 2014 at 4:26 Comment(5)
This helps us to avoid try catch!Exempt
However, it might double the complexity. Did anybody check?Tepper
@Tepper Time complexity is still linear but it will iterate through the list twice.Loppy
@Loppy That is obviously what I meant. Even if pedantically it is the same order of complexity, iterating twice might be a severe disadvantage in many use cases thus I brought it up. And we still don't know the answer...Tepper
@Tepper this likely does double the complexity, I believe the in operator on a list has linear runtime. @Loppy stated it would iterate twice which answers your question, and is right in saying that doubling the linear complexity is not a huge deal. I wouldn't call iterating over a list twice a severe disadvantage in many use cases, as complexity theory tells us that O(n) + O(n) -> O(2*n) -> O(n), ie- the change is typically neglibile.Scarron
C
63

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.

Cardiac answered 17/11, 2015 at 19:5 Comment(3)
What about lists of strings, lists of non-numeric objects, etc... ?Piwowar
This answer should be better posted here: #6294679Legion
This is the best one I have read. numpy arrays are far more efficient than Python lists. If the list is short it's no problem making a copy of it from a Python list, if it isn't then perhaps the developer should consider storing the elements in numpy array in the first place.Property
H
57

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.

Hines answered 22/8, 2017 at 3:8 Comment(0)
K
56

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?

Kaylakayle answered 16/5, 2013 at 16:45 Comment(2)
The 3rd method iterates twice over the list, right?Springtail
Re: "All of the proposed functions here": At the time of writing perhaps, but you ought to check newer answers to see if it is still true.Herpetology
D
35

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 arguments and return the position of the item in the list, like we saw before.

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

Output


[1, 3, 5, 7]

Simple

for n, i in enumerate([1, 2, 3, 4, 1]):
    if i == 1:
        print(n)

Output:

0
4
Dissolvent answered 8/8, 2017 at 5:1 Comment(1)
This answer should be better posted here: #6294679Legion
W
34
me = ["foo", "bar", "baz"]
me.index("bar") 

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

Worldbeater answered 17/4, 2022 at 8:50 Comment(0)
U
27

All indexes with the 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')
Umont answered 11/11, 2015 at 5:16 Comment(2)
This answer should be better posted here: #6294679Legion
enumerate(xs) is clearer than zip(xs, range(len(xs)). Also, this doesn't answer the question.Adenovirus
W
26

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]
Winkle answered 29/5, 2013 at 7:17 Comment(0)
A
22

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]
>>> 
Abra answered 29/5, 2013 at 19:17 Comment(2)
This answer should be better posted here: #6294679Legion
What does this have to do with the question?Adenovirus
V
22

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

Update

After another year of heads-down python development, I'm a bit embarrassed by my original answer, so to set the record straight, 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]
>>> 

And now, after reviewing this question and all the answers, I realize that this is exactly what FMc suggested in his earlier answer. At the time I originally answered this question, I didn't even see that answer, because I didn't understand it. 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 Google 'python list comprehension' 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.

Verbify answered 30/12, 2014 at 21:3 Comment(0)
R
20

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

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

Output: 1

Realpolitik answered 13/1, 2022 at 19:49 Comment(0)
H
17

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.

Higley answered 28/3, 2014 at 9:11 Comment(1)
This answer should be better posted here: #6294679Legion
J
16

Finding index of item x in list L:

idx = L.index(x) if (x in L) else -1
Jesseniajessey answered 25/5, 2018 at 21:56 Comment(3)
This iterates the array twice, thus it could result in performance issues for large arrays.Legion
@Legion - Correct. Not suitable if there is no reasonably low upper bound available for the list length.Jesseniajessey
Should be used only for non-repetitive tasks/deployments, or if the list length is relatively small enough to not affect overall performance noticeably.Jesseniajessey
S
14

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
Spheroid answered 17/5, 2015 at 3:21 Comment(0)
M
12

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"])
Manado answered 7/2, 2022 at 10:46 Comment(1)
Works nicely for integers and floats too, as well as finding all occurrencesJanik
C
11

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
Carrera answered 4/3, 2018 at 8:39 Comment(2)
however, JavaScript has the philosophy that weird results are better than errors, so it makes sense to return -1, but in Python, it can make a hard to track down bug, since -1 returns an item from the end of the list.Interne
-1 is not a weird result in java/javascript. It is a language convenction of "not found in list". It is possible to use this java intelligence in Python doing a simple verification: if theindex > -1: or if theindex >= 0: which does the same.Pashm
M
11

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") 
Monocyclic answered 28/8, 2020 at 9:35 Comment(1)
Calling a variable list overwrites a builtin function. Calling in, then index means you're doing two searches. Better to try/except .index() as suggested in other threads.Adenovirus
H
9

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.

Hamza answered 10/4, 2021 at 7:48 Comment(0)
O
8

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))))))
Ostraw answered 7/3, 2018 at 19:9 Comment(2)
This answer feels at home for Scala / functional-programming enthusiastsWaddle
When only a single value is needed in a list that has many matches this one takes long.Gombroon
G
8

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()]
Gombroon answered 22/6, 2020 at 16:2 Comment(2)
idx = next((i for i, v in enumerate(ls) if v == chk), -1) to get the behavior similar to str.index(chk).Arielle
@Arielle Decided to put some extra work into the answerGombroon
C
7
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

Cloe answered 5/7, 2015 at 13:12 Comment(0)
S
6

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

Scholastic answered 12/8, 2017 at 20:1 Comment(1)
[i for i,j in enumerate(haystack) if j==‘needle’] is more compact and readable, I think.Dissolvent
M
5

If performance is of concern:

It is mentioned in numerous answers that the built-in method of list.index(item) method is an O(n) algorithm. It is fine if you need to perform this once. But if you need to access the indices of elements a number of times, it makes more sense to first create a dictionary (O(n)) of item-index pairs, and then access the index at O(1) every time you need it.

If you are sure that the items in your list are never repeated, you can easily:

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

# Create the dictionary
myDict = dict((e,i) for i,e in enumerate(myList))

# Lookup
myDict["bar"] # Returns 1
# myDict.get("blah") if you don't want an error to be raised if element not found.

If you may have duplicate elements, and need to return all of their indices:

from collections import defaultdict as dd
myList = ["foo", "bar", "bar", "baz", "foo"]

# Create the dictionary
myDict = dd(list)
for i,e in enumerate(myList):
    myDict[e].append(i)

# Lookup
myDict["foo"] # Returns [0, 4]
Mendelism answered 10/9, 2018 at 18:51 Comment(0)
S
5

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
Succinctorium answered 3/4, 2020 at 16:50 Comment(1)
"Using bisect module on my machine is about 20 times faster than using index method." is a somewhat inaccurate way to describe the relationship between the two algorithms. It's not a linear relationship, so on small lists of, say, 10 elements, both algorithms should perform about the same. On slightly larger lists, you may begin to notice a difference. On massive lists, binary search may be thousands of times faster.Adenovirus
P
5

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


Postaxial answered 3/10, 2021 at 14:9 Comment(0)
E
4

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.

Escort answered 30/1, 2018 at 21:10 Comment(2)
It's only an example to understand how you can find repeated items - enumerate helps to do it.Escort
@Adenovirus I understood you about newlist variable that I used to define the result of enumerate(mylist). That's why I cut that line and put enumerate function on loop. And it's better now. Remembering that all everything is an object in Python, but you can call enumerate as "built-in" function as official documentation does, of course. And, when I use enumerate to put a list in order, I continue having a list. Otherwise, you would need to call it a dictionary, which is not the case.Escort
M
4
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 .

Meristic answered 7/1, 2022 at 0:8 Comment(1)
You can only binary search if the list is sorted, and sorting is O(n log(n)).Adenovirus
D
4

Try the following code:

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

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

Drip answered 2/10, 2022 at 9:35 Comment(0)
S
3

As indicated by @TerryA, many answers discuss how to find one index.

more_itertools is a third-party library with tools to locate multiple indices within an iterable.

Given

import more_itertools as mit


iterable = ["foo", "bar", "baz", "ham", "foo", "bar", "baz"]

Code

Find indices of multiple observations:

list(mit.locate(iterable, lambda x: x == "bar"))
# [1, 5]

Test multiple items:

list(mit.locate(iterable, lambda x: x in {"bar", "ham"}))
# [1, 3, 5]

See also more options with more_itertools.locate. Install via > pip install more_itertools.

Stenography answered 25/9, 2018 at 15:47 Comment(0)
P
3

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
Pix answered 14/11, 2018 at 18:49 Comment(1)
Does not work if the item is an instance of a classGombroon
C
2

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

Coeducation answered 29/12, 2021 at 18:49 Comment(0)
H
1

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]
Hamburg answered 18/3, 2019 at 9:32 Comment(0)
C
1

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
Caraviello answered 28/11, 2021 at 12:37 Comment(0)
A
1

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'
Adenovirus answered 14/5, 2023 at 2:45 Comment(0)
U
0

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.

Unbolted answered 14/12, 2022 at 14:36 Comment(0)
A
0

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
Arsenical answered 7/1, 2023 at 22:44 Comment(0)
C
0

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'
Crandell answered 22/9, 2023 at 11:35 Comment(0)
R
0

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
Rabat answered 26/10, 2023 at 18:14 Comment(0)
A
-1

Simple option:

a = ["foo", "bar", "baz"]
[i for i in range(len(a)) if a[i].find("bar") != -1]
Archaic answered 4/5, 2021 at 12:28 Comment(1)
Not every element in the list is string.Wildermuth
A
-1

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)
Attar answered 5/5, 2022 at 4:1 Comment(2)
zip(range(0,len(list1)),list1) is overkill when you could just do enumerate(list1)Homs
the code is an overkillRealpolitik

© 2022 - 2024 — McMap. All rights reserved.