簡體   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