Searching a list of objects in Python

Question:

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.

Asked By: m0j0

||

Answers:

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
Answered By: Johannes Weiss

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
Answered By: Adam Rosenfield
[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
Answered By: Markus Jarderot

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!"
Answered By: Charlie Martin
filter(lambda x: x.n == 5, myList)
Answered By: vartec

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:

Answered By: Tom Dunham

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
Answered By: gahooa

Consider using a dictionary:

myDict = {}

for i in range(20):
    myDict[i] = i * i

print(5 in myDict)
Answered By: dan-gph

Another way you could do it is using the next() function.

matched_obj = next(x for x in list if x.n == 10)
Answered By: SEMICS

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)
Answered By: Matt Koch
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.