Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python, Filter a List of Objects, but return a specific attribute?

Suppose I have a list of Person objects, which have an age and room_number attribute, and I have written a check() function, which returns True, if person.age() and person.room_number() are satisfactory, False otherwise.

filter(check, list_of_people_objects) would return a list of Person objects which satisfies the criteria of check()

However, my question is, is there a way of returning a list of each approved Person's room number without iterating through the list twice, like so without using list comprehension? So filtering, but returning a more specific attribute of the iterable.

map(lambda x: x.room_number(), filter(check, list_of_people_objects))

like image 599
zhuyxn Avatar asked Aug 15 '12 09:08

zhuyxn


2 Answers

There are in fact two ways.

  1. itertools

    map(..., itertools.ifilter(..))
    
  2. List comprehension

    [x.room_number() for x in people if check(x)]
    

Which you choose is mostly a matter of taste, but convention leans towards the latter.

like image 172
Ignacio Vazquez-Abrams Avatar answered Dec 07 '22 22:12

Ignacio Vazquez-Abrams


In the case of object filtering where you want to do an inclusive union of a subset of properties to equal a limited set of values and then perform any option (including list the attribute values) of the filtered list you can do the following using generators in a single statement (last line of code, the rest is there for instruction showing generating a large list of objects using matrix multiplication to generate constructor params)

#!/usr/bin/env python
import itertools
import pprint
class myObj(object):
    attr_1 = None
    attr_2 = None
    attr_3 = None
    def __init__(self, at1, at2, at3):
        self.attr_1 = at1
        self.attr_2 = at2
        self.attr_3 = at3
        super(myObj, self).__init__()

    def __repr__(self):
        return '<%s %s>' % (type(self), pprint.pformat(self.__dict__))

objs = itertools.starmap(myObj, itertools.product(iter('val_%d' % (i) for i in
    range(1,4)), repeat=3))

filter_dict = {
    'attr_1' : 'val_1',
    'attr_2' : 'val_2',
    'attr_3' : 'val_3',
}
print(list(result.attr_3 for result in objs if not list(False for pn,cval in
    filter_dict.items() if getattr(result, pn, None) != cval)))
like image 21
SkyLeach Avatar answered Dec 07 '22 23:12

SkyLeach