Finding a list of objects in Python

Suppose I create a simple class to work just like a C-style structure, to just store data items. I am trying to figure out how to search for a list of objects for objects with an attribute equal to a specific value. The following is a trivial example illustrating what I'm trying to do.

For example:

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 search myList to determine if it contains an element with n == 5?

I work at Google and look at Python docs and I think I could do this with a list, but I'm not sure. I can add that I have to use Python 2.4.3, so any new gee-whiz 2.6 or 3.x features are not available to me.

+50
python
Feb 28 '09 at 18:06
source share
8 answers

You can get a list of all the relevant items with a list:

 [x for x in myList if xn == 30] # list of all elements with .n==30 

If you just want to determine if the list contains any element that matches and does 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: xn == 3) # True if any element has .n==3 # do stuff 
+63
Feb 28 '09 at 18:11
source share

Simple, elegant and powerful:

Generator expression combined with built-in ... (python 2.5 +)

 any(x for x in mylist if xn == 10) 

Uses the built-in Python any() , which is defined as follows:

any (iterable) -> Return True if any iterable element is true. Equivalent to:

 def any(iterable): for element in iterable: if element: return True return False 
+45
Feb 28 '09 at 20:15
source share

Just for completeness, don't forget about Simplyest Thing, which could work:

 for i in list: if in == 5: # do something with it print "YAY! Found one!" 
+34
Feb 28 '09 at 18:20
source share
 filter(lambda x: xn == 5, myList) 
+24
Feb 28 '09 at 18:22
source share
 [x for x in myList if xn == 30] # list of all matches any(xn == 30 for x in myList) # if there is any matches [i for i,x in enumerate(myList) if xn == 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 xn == 30) # the first match, if any 
+23
Feb 28 '09 at 18:19
source share

You can use in to search for an item in the collection and to understand the list in order to extract the field of interest. 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:

+7
Feb 28 '09 at 18:23
source share

Consider using a dictionary:

 myDict = {} for i in range(20): myDict[i] = i * i print(5 in myDict) 
+3
Mar 01 '09 at 1:14
source share

You must add the __eq__ and __hash__ to your Data class, it can check if the __dict__ attributes __dict__ equal (the same properties), and then if their values ​​are equal.

If you have done this, you can use

 test = Data() test.n = 5 found = test in myList 

The in keyword checks if test in myList .

If you want only the a n property in Data , you can 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 
+1
Feb 28 '09 at 18:10
source share



All Articles