【发布时间】:2017-11-02 06:37:34
【问题描述】:
TL;DR
为具有可变维度键的字典实现过滤器功能的最有效方法是什么?过滤器应该采用与字典键相同维度的元组,并输出字典中与过滤器匹配的所有键,使得所有维度都为filter[i] is None or filter[i] == key[i]i。
在我当前的项目中,我需要处理包含大量数据的字典。字典的一般结构是这样的,它包含以 2 到 4 个整数作为键和整数作为值的元组。字典中的所有键都具有相同的维度。为了说明,以下是我需要处理的字典示例:
{(1, 2): 1, (1, 5): 2}
{(1, 5, 3): 2}
{(5, 2, 5, 2): 8}
这些词典包含大量条目,其中最大的词典约有 20 000 个条目。我经常需要过滤这些条目,但通常只查看键元组的某些索引。理想情况下,我想要一个可以提供过滤器元组的函数。然后该函数应返回与过滤器元组匹配的所有键。如果过滤器元组包含None 条目,那么它将匹配该索引处字典键元组中的任何值。
函数应该对具有二维键的字典执行的操作示例:
>>> dict = {(1, 2): 1, (1, 5): 2, (2, 5): 1, (3, 9): 5}
>>> my_filter_fn((1, None))
{(1, 2), (1, 5)}
>>> my_filter_fn((None, 5))
{(1, 5), (2, 5)}
>>> my_filter_fn((2, 4))
set()
>>> my_filter_fn((None, None))
{(1, 2), (1, 5), (2, 5), (3, 9)}
由于我的字典有不同的元组维度,我尝试通过编写一个考虑元组维度的生成器表达式来解决这个问题:
def my_filter_fn(entries: dict, match: tuple):
return (x for x in entries.keys() if all(match[i] is None or match[i] == x[i]
for i in range(len(key))))
不幸的是,与完全手动写出条件相比,这相当慢((match[0] is None or match[0] === x[0]) and (match[1] is None or match[1] == x[1]);对于 4 个维度,这大约慢了 10 倍。这对我来说是个问题,因为我需要经常进行此过滤。
以下代码演示了性能问题。提供代码只是为了说明问题并启用测试的重现。代码部分可以跳过,结果如下。
import random
import timeit
def access_variable_length():
for key in entry_keys:
for k in (x for x in all_entries.keys() if all(key[i] is None or key[i] == x[i]
for i in range(len(key)))):
pass
def access_static_length():
for key in entry_keys:
for k in (x for x in all_entries.keys() if
(key[0] is None or x[0] == key[0])
and (key[1] is None or x[1] == key[1])
and (key[2] is None or x[2] == key[2])
and (key[3] is None or x[3] == key[3])):
pass
def get_rand_or_none(start, stop):
number = random.randint(start-1, stop)
if number == start-1:
number = None
return number
entry_keys = set()
for h in range(100):
entry_keys.add((get_rand_or_none(1, 200), get_rand_or_none(1, 10), get_rand_or_none(1, 4), get_rand_or_none(1, 7)))
all_entries = dict()
for l in range(13000):
all_entries[(random.randint(1, 200), random.randint(1, 10), random.randint(1, 4), random.randint(1, 7))] = 1
variable_time = timeit.timeit("access_variable_length()", "from __main__ import access_variable_length", number=10)
static_time = timeit.timeit("access_static_length()", "from __main__ import access_static_length", number=10)
print("variable length time: {}".format(variable_time))
print("static length time: {}".format(static_time))
结果:
变长时间:9.625867042849316 静态时长:1.043319165662158
我希望避免创建三个不同的函数my_filter_fn2、my_filter_fn3 和my_filter_fn4 来覆盖我的字典的所有可能维度,然后使用静态维度过滤。我知道过滤可变尺寸总是比过滤固定尺寸慢,但希望它不会慢近 10 倍。由于我不是 Python 专家,我希望有一种聪明的方法可以重新制定我的可变维度生成器表达式,以提供更好的性能。
按照我描述的方式过滤庞大字典的最有效方法是什么?
【问题讨论】:
-
对你的对象使用内置名称是不好的,所以
filter应该重命名(例如filter_entries) -
@AzatIbrakov 谢谢,我改了。
标签: python performance dictionary filtering