【问题标题】:Find object by its member inside a List in python在python的List中通过其成员查找对象
【发布时间】:2012-06-07 04:25:40
【问题描述】:

让我们假设以下简单对象:

class Mock:
    def __init__(self, name, age):
        self.name = name
        self.age = age

然后我有一个列表,其中包含一些像这样的对象:

myList = [Mock("Dan", 34), Mock("Jack", 30), Mock("Oli", 23)...]

是否有一些内置功能可以让我获得所有年龄为 30 岁的 Mocks? 当然我可以遍历他们并比较他们的年龄,但是像

find(myList, age=30)

会很好。有这样的吗?

【问题讨论】:

    标签: python list search find


    【解决方案1】:

    你可以试试filter():

    filter(lambda x: x.age == 30, myList)
    

    这将返回一个列表,其中仅包含满足 lambda 表达式的对象。

    【讨论】:

    • 如果您打算经常通过此属性进行查找,您可能希望基于该属性维护一个dict
    • 至少对于 Python 3.5,你需要list(filter(lambda x: x.age == 30, myList)) 来获取列表。
    • 使用 filter() 是旧的经典答案,但列表推导式在 Python 版本之间更快且更便携,如其他答案中所述。
    【解决方案2】:

    列表推导可以选择这些:

    new_list = [x for x in myList if x.age == 30]
    

    【讨论】:

    • 也是不错的解决方案,但@dcrooney 答案更适合该功能。有没有人比较什么更快?
    • timeit 在我的机器上为列表理解提供了大约 0.30 微秒,为 lambda 过滤器提供了 0.58 微秒。但它们在这里基本上是等价的,所以你应该使用你喜欢的那个。
    • 这里也对这个问题进行了一些很好的讨论:stackoverflow.com/a/1247490/317172
    【解决方案3】:

    您可能希望对它们进行预索引 -

    from collections import defaultdict
    
    class Mock(object):
        age_index = defaultdict(list)
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
            Mock.age_index[age].append(self)
    
        @classmethod
        def find_by_age(cls, age):
            return Mock.age_index[age]
    

    编辑:一张图片胜过千言万语:

    X 轴是 myList 中的 Mocks 数量,Y 轴是运行时间,以秒为单位。

    • 红点是@dcrooney 的 filter() 方法
    • 蓝点是@marshall.ward 的列表理解
    • 隐藏在 X 轴后面的绿点是我的索引 ;-)

    【讨论】:

    • 非常感谢您的回答。我正要手动重新实现类似的东西。
    • 谢谢。和漂亮的图表。但讨论各种权衡会有所帮助,例如建立索引的额外启动时间,以及它所需的空间。
    • 这是一个很好的解决方案,但您确实会冒以下风险:1. 更高的内存使用率 2. 更多的 CPU 使用率来预计算列表。对于大型列表,这可能会令人望而却步。
    【解决方案4】:

    列表推导式几乎总是做这些事情的更快方法(这里是 2 倍),尽管如前所述,如果您关心速度,索引会更快。

    ~$ python -mtimeit -s"from mock import myList" "filter(lambda x: x.age==21, myList)"
    1000000 loops, best of 3: 1.34 usec per loop
    ~$ python -mtimeit -s"from mock import myList" "[x for x in myList if x.age==21]"
    1000000 loops, best of 3: 0.63 usec per loop
    

    对于当前目录下的文件mock.py

    class Mock:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    myList = [Mock('Tom', 20), Mock('Dick', 21), Mock('Harry', 21), Mock('John', 22)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-29
      • 2012-04-06
      • 2015-10-05
      • 1970-01-01
      • 2017-05-10
      • 2012-05-26
      • 2019-01-05
      相关资源
      最近更新 更多