Let's assume I'm creating a simple class to work similar to a C-style struct, to just hold data elements. I'm trying to figure out how to search a list of objects for objects with an attribute equaling a certain value. Below is a trivial example to illustrate what I'm trying to do.
For instance:
class Data:
pass
myList = []
for i in range(20):
data = Data()
data.n = i
data.n_squared = i * i
myList.append(data)
How would I go about searching the myList list to determine if it contains an element with n == 5?
I've been Googling and searching the Python docs, and I think I might be able to do this with a list comprehension, but I'm not sure. I might add that I'm having to use Python 2.4.3 by the way, so any new gee-whiz 2.6 or 3.x features aren't available to me.
To find an element in the list, use the Python list index() method, The index() is an inbuilt Python method that searches for an item in the list and returns its index. The index() method finds the given element in the list and returns its position.
Filter a Python List with filter() The filter(function, iterable) function takes a function as input that takes on argument (a list element) and returns a Boolean value whether this list element should pass the filter. All elements that pass the filter are returned as a new iterable object (a filter object).
A simple solution is to use the list. sort() function to sort a collection of objects (using some attribute) in Python. This function sorts the list in-place and produces a stable sort. It accepts two optional keyword-only arguments: key and reverse.
To check if the list contains an element in Python, use the “in” operator. The “in” operator checks if the list contains a specific item or not. It can also check if the element exists on the list or not using the list.
You can get a list of all matching elements with a list comprehension:
[x for x in myList if x.n == 30] # list of all elements with .n==30
If you simply want to determine if the list contains any element that matches and do it (relatively) efficiently, you can do
def contains(list, filter):
for x in list:
if filter(x):
return True
return False
if contains(myList, lambda x: x.n == 3) # True if any element has .n==3
# do stuff
Simple, Elegant, and Powerful:
A generator expression in conjuction with a builtin… (python 2.5+)
any(x for x in mylist if x.n == 10)
Uses the Python any()
builtin, which is defined as follows:
any(iterable)
->
Return True if any element of the iterable is true. Equivalent to:
def any(iterable):
for element in iterable:
if element:
return True
return False
Just for completeness, let's not forget the Simplest Thing That Could Possibly Work:
for i in list:
if i.n == 5:
# do something with it
print "YAY! Found one!"
[x for x in myList if x.n == 30] # list of all matches
[x.n_squared for x in myList if x.n == 30] # property of matches
any(x.n == 30 for x in myList) # if there is any matches
[i for i,x in enumerate(myList) if x.n == 30] # indices of all matches
def first(iterable, default=None):
for item in iterable:
return item
return default
first(x for x in myList if x.n == 30) # the first match, if any
filter(lambda x: x.n == 5, myList)
You can use in
to look for an item in a collection, and a list comprehension to extract the field you are interested in. This (works for lists, sets, tuples, and anything that defines __contains__
or __getitem__
).
if 5 in [data.n for data in myList]:
print "Found it"
See also:
Another way you could do it is using the next() function.
matched_obj = next(x for x in list if x.n == 10)
You should add a __eq__
and a __hash__
method to your Data
class, it could check if the __dict__
attributes are equal (same properties) and then if their values are equal, too.
If you did that, you can use
test = Data()
test.n = 5
found = test in myList
The in
keyword checks if test
is in myList
.
If you only want to a a n
property in Data
you could use:
class Data(object):
__slots__ = ['n']
def __init__(self, n):
self.n = n
def __eq__(self, other):
if not isinstance(other, Data):
return False
if self.n != other.n:
return False
return True
def __hash__(self):
return self.n
myList = [ Data(1), Data(2), Data(3) ]
Data(2) in myList #==> True
Data(5) in myList #==> False
Consider using a dictionary:
myDict = {}
for i in range(20):
myDict[i] = i * i
print(5 in myDict)
Use the following list comprehension in combination with the index
method:
data_n = 30
j = [data.n for data in mylist].index(data_n)
print(mylist[j].data.n == data_n)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With