【问题标题】:Python, Filter a List of Objects, but return a specific attribute?Python,过滤对象列表,但返回特定属性?
【发布时间】:2012-08-11 14:36:27
【问题描述】:

假设我有一个 Person 对象列表,其中有一个 age 和 room_number 属性,并且我编写了一个 check() 函数,它返回 True,如果 person.age() 和 person.room_number() 都令人满意,则返回 False否则。

filter(check, list_of_people_objects) 将返回满足check() 条件的 Person 对象列表

但是,我的问题是,有没有一种方法可以返回每个已批准人员的房间号列表,而无需遍历列表两次,例如不使用列表理解? 所以过滤,但返回迭代的更具体的属性。

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

【问题讨论】:

    标签: python map filter itertools


    【解决方案1】:

    其实有两种方式。

    1. itertools

      map(..., itertools.ifilter(..))
      
    2. 列表理解

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

    您选择哪一种主要取决于口味,但惯例倾向于后者。

    【讨论】:

    • 谢谢,使用 ifilter 和 filter 有区别吗?我知道列表理解会起作用(如问题中所述),但希望有一种巧妙的方式使用 itertools/map/filter 只使用一次迭代 D:
    • ifilter() 返回一个生成器而不是一个序列,因此在迭代之前实际上不会检查任何内容。
    【解决方案2】:

    在对象过滤的情况下,您希望对属性子集进行包容性联合以等于一组有限的值,然后执行过滤列表的任何选项(包括列出属性值),您可以执行以下操作在单个语句中使用生成器(最后一行代码,其余用于显示使用矩阵乘法生成大量对象以生成构造函数参数的指令)

    #!/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)))
    

    【讨论】:

      【解决方案3】:
      class Person():
          def __init__(self,age,room):
              self.age=age
              self.room=room
          def check(self)    :
              if self.room>300 and self.age>15:
                  return True
              else:
                  return False
      

      输出:

      >>> a=Person(20,285)
      >>> b=Person(22,990)
      >>> c=Person(12,958)
      >>> d=Person(18,150)
      >>> room=[]
      >>> filterd=[]
      >>> for x in (a,b,c,d):
          if x.check():
              room.append(x.room)
              filterd.append(x)
      
      
      >>> room
      [990]
      >>> filterd
      [<__main__.Person object at 0xa94c94c>]
      

      【讨论】:

        猜你喜欢
        • 2020-07-23
        • 2022-01-01
        • 2012-07-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-15
        • 2018-10-19
        • 2021-12-16
        相关资源
        最近更新 更多