Given a list ["foo", "bar", "baz"]
and an item in the list "bar"
, how do I get its index 1
?
"bar"
, [2] All the indices of "bar"
? - anyone >>> ["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.
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.
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.
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.
Answered 2023-09-20 20:11:55
index()
is just under 90% faster than list comprehension against lists of integers. - anyone 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
Answered 2023-09-20 20:11:55
izip
should be replaced by the built in zip
. See here - anyone 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]
- anyone To get all indexes:
indexes = [i for i, x in enumerate(xs) if x == 'foo']
Answered 2023-09-20 20:11:55
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"])
Answered 2023-09-20 20:11:55
a = ["foo","bar","baz",'bar','any','much']
indexes = [index for index in range(len(a)) if a[index] == 'bar']
Answered 2023-09-20 20:11:55
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
Answered 2023-09-20 20:11:55
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
Answered 2023-09-20 20:11:55
in
operator on a list has linear runtime. @ApproachingDarknessFish 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. - anyone 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.
Answered 2023-09-20 20:11:55
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:
ValueError
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)
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)
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]
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.
Answered 2023-09-20 20:11:55
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?
Answered 2023-09-20 20:11:55
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]
>>>
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]
for n, i in enumerate([1, 2, 3, 4, 1]):
if i == 1:
print(n)
Output:
0
4
Answered 2023-09-20 20:11:55
me = ["foo", "bar", "baz"]
me.index("bar")
You can apply this for any member of the list to get their index
Answered 2023-09-20 20:11:55
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')
Answered 2023-09-20 20:11:55
enumerate(xs)
is clearer than zip(xs, range(len(xs))
. Also, this doesn't answer the question. - anyone 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]
Answered 2023-09-20 20:11:55
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]
>>>
Answered 2023-09-20 20:11:55
... 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]
>>>
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.
Answered 2023-09-20 20:11:55
Here's a two-liner using Python's index()
function:
LIST = ['foo' ,'boo', 'shoo']
print(LIST.index('boo'))
Output: 1
Answered 2023-09-20 20:11:55
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.
Answered 2023-09-20 20:11:55
Finding index of item x in list L:
idx = L.index(x) if (x in L) else -1
Answered 2023-09-20 20:11:55
This solution is not as powerful as others, but if you're a beginner and only know about for
loops 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
Answered 2023-09-20 20:11:55
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")
Answered 2023-09-20 20:11:55
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. - anyone 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"])
Answered 2023-09-20 20:11:55
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.
Answered 2023-09-20 20:11:55
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))))))
Answered 2023-09-20 20:11:55
Scala
/ functional-programming enthusiasts - anyone 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:
try:
index = array.index('search_keyword')
except ValueError:
index = -1
Answered 2023-09-20 20:11:55
# Throws ValueError if nothing is found
some_list = ['foo', 'bar', 'baz'].index('baz')
# some_list == 2
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())
index_of_staff_members = [
i for i, user in enumerate(users)
if user.is_staff()]
Answered 2023-09-20 20:11:55
idx = next((i for i, v in enumerate(ls) if v == chk), -1)
to get the behavior similar to str.index(chk). - anyone 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
Answered 2023-09-20 20:11:55
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.)
Answered 2023-09-20 20:11:55
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]
Answered 2023-09-20 20:11:55
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
Answered 2023-09-20 20:11:55