Get index in the list of objects by attribute in Python
Question:
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?
Answers:
You can use enumerate
:
for index, item in enumerate(my_list):
if item.id == 'specific_id':
break
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)
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
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)]
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
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?
You can use enumerate
:
for index, item in enumerate(my_list):
if item.id == 'specific_id':
break
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)
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
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)]
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