繁体   English   中英

如何按字段值过滤对象集合?

[英]How to filter a collection of objects by field value?

如何在 Python 中按字段值组织和过滤对象集合? 我需要通过等于一个精确值和小于一个值来过滤。

以及如何有效地做到这一点? 如果我将我的对象存储在一个列表中,我需要遍历整个列表,可能包含数十万个对象。

@dataclass
class Person:
  name: str
  salary: float
  is_boss: bool


# if to store objects in a list...
collection = [Person("Jack", 50000, 0), ..., Person("Jane", 120000, 1)]

# filtering in O(n), sloooooow
target = 100000
filtered_collection = [x for x in collection if salary < target]

PS:实际上我的用例是按某个字段分组,即is_boss并按另一个过滤,即salary 怎么做? 我应该在排序列表上使用itertools.groupby并使我的对象具有可比性吗?

如果您按排序顺序维护您的list (理想情况下,这意味着很少插入或删除,因为中间list插入/删除本身就是O(n) ),您可以使用bisect模块找到低于给定薪水的Person集合。

from bisect import bisect
from operator import attrgetter

# if to store objects in a list...
collection = [Person("Jack", 50000, 0), ..., Person("Jane", 120000, 1)]
collection.sort(key=attrgetter('salary'))  # O(n log n) initial sort

# filtering searches in O(log n):
target = 100000
filtered_collection = collection[:bisect(collection, target, key=attrgetter('salary'))]

注意:各种bisect模块函数的key参数仅在 3.10 中受支持。 在以前的版本中,您需要根据salaryPerson定义丰富的比较运算符并搜索伪造的Person对象,或者维护丑陋的单独排序list 、仅salary之一和Person对象的并行list .

要将单个元素添加到collection中,您可以使用bisectinsort函数。 或者您可以将一堆项目批量添加到list的末尾并使用与以前相同的key (Python 的排序算法 TimSort,当集合大部分已经有序时,性能接近O(n) ,所以成本没有你想象的那么高)。

我会注意到,在实践中,这种场景(可以按多个字段任意排序的海量数据)通常需要数据库; 您可能会考虑使用sqlite3 (如果需要,最终切换到更生产级的数据库,如 MySQL 或 PostGres),在定义了适当的索引后,您可以在任何索引字段上执行O(log n) SELECT 您可以在提取实际需要使用的数据时转换为Person对象。 真正的 DBMS 解决方案提供的 B 树让您在索引字段上的插入、删除和选择工作量为O(log n) ,而 Python 内置的集合类型让您选择; 只有插入/删除或搜索中的一个可以真正是O(log n) ,而另一个是O(n)

数组有一个排序方法——你所要做的就是创建一个函数来判断一个对象是否大于另一个对象——让我告诉你

class Foo:
    def __init__(bar):
        this.bar = bar

fooArray = [Foo(10),Foo(8),Foo(9)]
def sortFoo(foo):
    return foo.bar

fooArray.sort(key=sortFoo)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM