46

I have list of objects with attribute id and I want to find index of object with specific id. I wrote something like this:

index = -1
for i in range(len(my_list)):
    if my_list[i].id == 'specific_id'
        index = i
        break

but it doesn't look very well. Are there any better options?

2
  • Looping by index is a really huge anti-pattern in Python - loop directly over a list. Commented Oct 3, 2013 at 14:53
  • Can't believe I am saying this but I miss JavaScript for things like this Commented Nov 1, 2024 at 9:24

5 Answers 5

78

Use enumerate when you want both the values and indices in a for loop:

for index, item in enumerate(my_list):
    if item.id == 'specific_id':
        break
else:
    index = -1

Or, as a generator expression:

index = next((i for i, item in enumerate(my_list) if item.id == 'specific_id'), -1)
Sign up to request clarification or add additional context in comments.

2 Comments

But "-1" is a valid index value. If your code doesn't find a match, it will return an index of -1, and lead someone to take the final element of the list as though it matched.
@CPBL That's true. It would certainly be more pythonic to raise a ValueError in the else clause (to mirror the behavior of list.index).
14

Here's an alternative that doesn't use an (explicit) loop, with two different approaches to generating the list of 'id' values from the original list.

try:
    # index = map(operator.attrgetter('id'), my_list).index('specific_id')
    index = [ x.id for x in my_list ].index('specific_id')
except ValueError:
    index = -1

2 Comments

Is this in python 3 only? Using python 2.7.4 'find' doesn't exist - the method that finds the index of an element in a list is called 'index'.
No, this just appears to be a disaster of an answer. Not only did I appear to assume there was a list.find by analogy to the pair of str.find and str.index methods, but also mixed up which one raises a ValueError (it's str.index, not str.find) and which returns -1. Corrected to list.index now.
11

You can use enumerate:

for index, item in enumerate(my_list):
    if item.id == 'specific_id':
        break

Comments

4

Implement the __eq__ method for your class

class MyCls:
   def __init__(self, id):
       self.id = id

   def __eq__(self, other):
       # comparing with str since you want to compare
       # your object with str

       if not isinstance(other, str):
           raise TypeError("MyCls can be compared only with str")
       if other == self.id:
           return True
       return False

now you can do something like

my_list = [MyCls(i) for i in 'abcdef']
print(my_list.index('c'))

This would return the index 2. It would behave like normal list.index methods behaves. i.e If it doesn't find the index, it will raise a ValueError

Comments

-1

Assuming

a = [1,2,3,4]
val = 3

Do

a.index(val) if val in a else -1

For multiple occurrence, as per Azam's comment below:

[i if val == x else -1 for i,x in enumerate(a)] 

Edit1: For everyone commenting that its List of object, all you need is, access the id

[i if val == x.id else -1 for i,x in enumerate(a)] 

3 Comments

what if the val number that we are searching for is repeating such as a=[1,2,3,4,3,7,9]???
is a = [1,2,3,4] a list of objects ? Please read the op's question before answering
this is not a list of objects

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.