ichigo
ichigo

Reputation: 327

Searching within a list of Objects in Python

Lets assume the following object:

class Test:
    id1 = ""
    id2 = ""
    id3 = ""

    def __init__(self,arg1,arg2,arg3):
        self.id1 = arg1
        self.id2 = arg2
        self.id3 = arg3

As it can be seen, this class must contain 3 unique ids.

t = []
t.append(Test(200,201,193))
t.append(Test(403,221,213))
t.append(Test(3,523,2003))

Assuming the code above, what would be the easiest way for me to find the object with id1 = 403, id2 = 221, and id3 =213 in the list t?

Thanks in advance.

Upvotes: 1

Views: 223

Answers (4)

Jonathan Livni
Jonathan Livni

Reputation: 107212

In case you have a lot of objects and you need to find a match many times, it may be more efficient to first pre-process them into a dictionary with a key of (id1,id2,id3). That way you'll be able to find the object in O(1).

To build the dict:

# In Python 2.7+
the_dict = {(o.id1, o.id2, o.id3) : o for o in objects}
# In Python 2.6-
the_dict = dict((o.id1, o.id2, o.id3),o) for o in objects)

Then to find the object in O(1):

the_dict[(id1,id2,id3)]

Note that placing the objects as dictionary values does not copy them (Python never copies implicitly), so you should not have to worry much about the memory impact.

Upvotes: 2

alexis
alexis

Reputation: 50220

If you need to store your objects in a list (i.e., if you can't use a dict and avoid the searching entirely), I would add a method to Test that returns the IDs as a tuple:

class Test(object):
    ...
    def getids(self):
        return (self.id1, self.id2, self.id3)

You can then simply loop and check against your tuple of ids to search for:

for obj in t:
    if obj.getids() == (403, 221, 213):
        return obj

This is "easy" as in cleaning up the interface. To speed it up, you should use a dictionary instead of a list and you can retrieve your objects in one step:

t = dict()  
obj = Test(403, 221, 213)
t[obj.getids()] = obj      # Store in dictionary, using ID as the key

You can then retrieve objects by ID, or check if they are present in t, in any of these ways:

found = t[(403, 221, 213)]       # returns object or raises KeyError
found = t.get((403, 221, 213))   # returns object or returns None
if (403, 221, 213) in t:         # True or False

Upvotes: 1

Chris Morgan
Chris Morgan

Reputation: 90852

Use iteration with comparison.

matches = [i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3]

If you know it's there and there's only one, you can do it this way:

match = next(i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3)

Note, though, that this will raise StopIteration if there is no such item. next can take a default value, though, so if you're not sure that it will exist, you could specify a default value:

match = next((i for i in t if i.id1 == id1 and i.id2 == id2 and i.id3 == id3), None)

Upvotes: 2

kev
kev

Reputation: 161914

>>> [x for x in t if x.id1==200 and x.id2==201 and x.id3==193]
[<__main__.Test object at 0x00BA3030>]

Upvotes: 1

Related Questions