Problem
I have a list of items. I’m looking for one (first or whatever) item in this list that has value as an attribute (or method result – whatever).
What is the most effective method of locating it?
Here’s test case:
class Test:
def __init__(self, value):
self.value = value
import random
value = 5
test_list = [Test(random.randint(0,100)) for x in range(1000)]
# that I would do in Pascal, I don't believe it's anywhere near 'Pythonic'
for x in test_list:
if x.value == value:
print "i found it!"
break
I don’t believe that utilizing generators and reduce() will make a difference because we’ll still be iterating through a list.
ps. : This is only an example of an equation to value. Of course, we want an element that can be used in every situation.
Asked by seler
Solution #1
next((x for x in test_list if x.value == value), None)
This retrieves the first item from the list that matches the condition, or None if none do. It’s the single-expression form I favor.
However,
for x in test_list:
if x.value == value:
print("i found it!")
break
The naive loop-break version, is perfectly Pythonic — it’s concise, clear, and efficient. To make it match the behavior of the one-liner:
for x in test_list:
if x.value == value:
print("i found it!")
break
else:
x = None
If you don’t break out of the loop, None will be assigned to x.
Answered by agf
Solution #2
It was just included for the sake of completeness because it had not been discussed previously. The good ol’ filter to filter your elements to be filtered.
Functional programming ftw.
####### Set Up #######
class X:
def __init__(self, val):
self.val = val
elem = 5
my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]
####### Set Up #######
### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
# File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
# print(next(my_filter_iter).value)
# StopIteration
# You can do that None stuff or whatever at this point, if you don't like exceptions.
I’m aware that list comprehensions are favoured in Python, or at least that’s what I’ve read, but to be honest, I don’t see the problem. Of course, Python is not a functional programming language, but Map, Reduce, and Filter are the most common use cases in functional programming.
So there you have it. Know what you’re doing when it comes to functional programming.
filter condition list
It doesn’t get much simpler than this:
next(filter(lambda x: x.val == value, my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions
Answered by Nima Mousavi
Solution #3
Consider the following scenario: The following is the array we have.
li = [{"id":1,"name":"ronaldo"},{"id":2,"name":"messi"}]
We now need to locate the object in the array with the id e.
next(x for x in li if x["id"] == 1 )
[x for x in li if x["id"] == 1 ][0]
def find(arr , id):
for x in arr:
if x["id"] == id:
return x
find(li , 1)
‘id’: 1, ‘name’: ‘ronaldo’ is the output of all the previous procedures.
Answered by Mohammad Nazari
Solution #4
This is an old question, but I use it pretty often (for version 3.8). It’s a little syntactic salt, but it beats the top answer in that you can get a list of results (if there are any) by eliminating the [0], and it still defaults to None if nothing is found. Simply change the x.value==value to whatever you’re looking for in any other condition.
_[0] if (_:=[x for x in test_list if x.value==value]) else None
Answered by Colin Hicks
Solution #5
You may also utilize the __eq__ function in your Test class to provide rich comparison and use the in operator. I’m not sure if this is the best method on its own, but it might be beneficial if you need to compare Test instances based on value somewhere else.
class Test:
def __init__(self, value):
self.value = value
def __eq__(self, other):
"""To implement 'in' operator"""
# Comparing with int (assuming "value" is int)
if isinstance(other, int):
return self.value == other
# Comparing with another Test object
elif isinstance(other, Test):
return self.value == other.value
import random
value = 5
test_list = [Test(random.randint(0,100)) for x in range(1000)]
if value in test_list:
print "i found it"
Answered by tm-
Post is based on https://stackoverflow.com/questions/7125467/find-object-in-list-that-has-attribute-equal-to-some-value-that-meets-any-condi