简体   繁体   English

从此Python生成器中删除递归

[英]Remove recursion from this Python generator

I have a generator that iterates over all combinations of keys up to a particular depth in a nested dictionary: 我有一个生成器,可以对嵌套字典中特定深度的所有键组合进行迭代:

def iter_dict(levels, input_dict, items=[], sort=False, **sort_args):
    for dict_key, val in (sorted(input_dict.items(), **sort_args) if
                          sort else input_dict.items()):
        if levels == 1:
            yield items + [(dict_key, val)]
        else:
            yield from iter_dict(levels - 1, val, items + [(dict_key, val)])

So it acts like so: 因此它的行为如下:

>>> d = {'a': 1, 'b': 2}
>>> list(iter_dict(1, d))
[[('a', 1)], [('b', 2)]]

And

>>> d = {'a': {'c': 1}, 'b': {'d' : 2}}
>>> list(iter_dict(1, d))
[[('a', {'c': 1})], [('b', {'d': 2})]]
>>> list(iter_dict(2, d))
[[('a', {'c': 1}), ('c', 1)], [('b', {'d': 2}), ('d', 2)]]

Each iteration on the generator returns a list of tuples, with the nth tuple being (key, value) at a depth of n into the nested dictionary. 生成器上的每次迭代都会返回一个元组列表,第n个元组是嵌套字典中深度为n的(key, value)

But I am implementing this function on huge dictionaries and am worried about reaching the maximum recursion depth level. 但是我正在庞大的词典上实现此功能,并且担心达到最大递归深度级别。

How can I rewrite the generator to remove the recursion? 如何重写生成器以删除递归?

But I am implementing this function on huge dictionaries and am worried about reaching the maximum recursion depth level 但是我正在庞大的词典上实现此功能,并且担心达到最大递归深度级别

Unless your dictionaries actually have 1000+ levels of nesting, this should not be a problem. 除非您的词典实际具有1000多个级别的嵌套,否则这不是问题。 Maximum recursion depth is really only about the depth ; 最大递归深度实际上只是深度 ; the branching factor is not an issue. 分支因素不是问题。 That is, it can be quite an issue wrt running time, but you won't get a maximum recursion depth error from that (and the running time will be just the same without recursion). 也就是说,这对于运行时间可能是一个很大的问题,但是您不会从中得到最大的递归深度错误(如果没有递归,运行时间将是相同的)。

How can I rewrite the generator to remove the recursion? 如何重写生成器以删除递归?

I guess this can be done using a stack and storing sequences of keys on the stack (all the keys to the current sub-dict). 我猜这可以通过使用堆栈并在堆栈上存储键序列(当前子字典的所有键)来完成。 Such a solution will probably be a bit more involved and not as elegant as the recursive algorith, so given the above, I don't think it's worth the effort. 这样的解决方案可能会涉及更多点,并且不如递归算法那么优雅,因此鉴于上述情况,我认为不值得为此付出努力。

But whatever, here you go (slightly simplified, without the sorting): 但是,无论如何,您可以进行以下操作(略有简化,无需排序):

from functools import reduce
def iter_dict(levels, input_dict):
    def get_nested(keys):
        return reduce(lambda d, k: d[k], keys, input_dict)
    stack = [[k] for k in input_dict]
    while stack:
        keys = stack.pop()
        if len(keys) == levels:
            yield [(k, get_nested(keys[:i])) for i, k in enumerate(keys, 1)]
        else:
            stack.extend(keys + [k] for k in get_nested(keys))

Example: 例:

>>> d = {'a': {'c': 1, "e": 2}, 'b': {'d' : 3, "f": 4}}
>>> list(iter_dict(2, d))
[[('a', {'c': 1, 'e': 2}), ('e', 2)],
 [('a', {'c': 1, 'e': 2}), ('c', 1)],
 [('b', {'d': 3, 'f': 4}), ('f', 4)],
 [('b', {'d': 3, 'f': 4}), ('d', 3)]]

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

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