高效地原地过滤一个字典

5
我们有一个字典 d1 和一个条件 cond。我们希望 d1 只包含满足条件 cond 的值。一种方法是:
d1 = {k:v for k,v in d1.items() if cond(v)}

然而,这样会创建一个新的字典,如果 d1 很大,则可能非常浪费内存。

另一种选择是:

for k,v in d1.items():
    if not cond(v):
       d1.pop(k)

但是,在迭代过程中修改字典会导致错误:“RuntimeError: dictionary changed size during iteration”。

在Python3中,如何正确地就地(in-place)过滤字典?


1
你为什么认为第一种方法效率低?在Python 3中,d1.items()只创建了一个视图,而不是复制字典。 - Chris_Rands
@Chris_Rands 但是,命令“{k:v for k,v in d1.items() if cond(v)}”不是创建一个新字典,然后将其放入变量“d1”中吗? - Erel Segal-Halevi
3
明白了,所以你希望最大化内存效率?我会投票重新打开这个问题,因为这个重复问题是关于速度的。 - Chris_Rands
满足 cond(v) 的键集是否很大?此外,您预计d1会变得多大? - Joel Cornett
根据您的内存限制,复制该结构可能是完全可接受的。如果内存使用是一个问题,您可以考虑创建包装器“视图”类,这些类的行为类似于字典,但在查找键时会惰性地调用 cond - Joel Cornett
显示剩余2条评论
1个回答

2
如果满足条件的键对应的值不多,那么您可以先聚合键,然后修剪字典:
for k in [k for k,v in d1.items() if cond(v)]:
    del d1[k]

如果列表 [k for k,v in d1.items() if cond(v)] 太大,可以将字典“分段”处理,即收集键直到它们的数量不超过阈值,修剪字典,并重复此过程,直到没有更多满足条件的键为止:

from itertools import islice

def prune(d, cond, chunk_size = 1000):
    change = True
    while change:
        change = False

        keys = list(islice((k for k,v in d.items() if cond(v)), chunk_size))
        for k in keys:
            change = True
            del d[k]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接