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
条目,则这将匹配该索引处字典的关键元组中的任何值。功能应该字典做什么用2维方向键
例子:
>>> 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))
结果:
variable length time: 9.625867042849316 static length time: 1.043319165662158
我想避免创建三个不同的功能my_filter_fn2
,my_filter_fn3
和my_filter_fn4
覆盖我的字典中所有可能的尺寸,然后用静态维度筛选。我知道对可变维度进行过滤总是比对固定维度进行过滤要慢,但希望它不会慢10倍。由于我不是Python专家,我希望有一种巧妙的方式可以重构我的可变维度生成器表达式,以提供更好的性能。
以我描述的方式过滤巨大词典的最有效方法是什么?
它是不好用的内置插件名称为对象,所以'filter'应该改名(以'filter_entries'例如) –
@AzatIbrakov谢谢你,我改变了它。 – Chris