Python如何高效处理复杂的嵌套字典

Ξέν*_*νος 5 python recursion dictionary nested python-3.x

我有一个复杂的嵌套字典,结构如下:

example = {
    ('rem', 125): {
        ('emo', 35): {
            ('mon', 133): {
                ('ony', 33): 0
            },
            ('mor', 62): {
                ('ore', 23): 0
            },
            ('mot', 35): {
                ('ote', 22): 0
            },
            ('mos', 29): {
                ('ose', 29): 0
            }
        },
        ('emi', 32): {
            ('min', 109): {
                ('ine', 69): 0
            },
            ('mit', 58): {
                ('ite', 64): 0,
                ('ity', 45): 0
            }
        },
        ('eme', 26): {
            ('mer', 68): {
                ('ere', 24): 0,
                ('ery', 20): 0
            }
        }
    },
    ('iro', 30): {
        ('ron', 27): {
            ('oni', 94): {
                ('nic', 205): 0
            },
            ('one', 47): {
                ('ned', 86): 0,
                ('ner', 85): 0,
                ('nes', 26): 0,
                ('net', 20): 0
            },
            ('ona', 44): {
                ('nal', 246): 0
            }
        }
    },
    ('det', 122): {
        ('ete', 53): {
            ('ter', 212): {
                ('ery', 72): 0,
                ('era', 35): 0
            },
            ('ten', 65): {
                ('ene', 21): 0
            }
        }
    },
    ('uni', 217): {
        ('nin', 62): {
            ('ine', 32): {
                ('ned', 88): 0,
                ('ner', 74): 0,
                ('net', 25): 0
            }
        },
        ('nim', 31): {
            ('ima', 50): {
                ('mal', 23): 0
            }
        },
        ('niv', 25): {
            ('ive', 28): {
                ('ver', 48): 0
            }
        }
    },
    ('nat', 66): {
        ('ati', 21): {
            ('tiv', 517): {
                ('ive', 821): 0
            },
            ('tin', 230): {
                ('ine', 134): 0,
                ('ina', 22): 0
            },
            ('tic', 187): {
                ('ice', 23): 0
            },
            ('tis', 129): {
                ('ise', 25): 0
            },
            ('tiz', 59): {
                ('ize', 100): 0
            },
            ('tit', 52): {
                ('ite', 60): 0
            },
            ('tif', 43): {
                ('ify', 30): 0
            },
            ('til', 25): {
                ('ile', 79): 0,
                ('ily', 37): 0
            }
        }
    },
    ('mar', 286): {
        ('ari', 30): {
            ('rin', 156): {
                ('ine', 168): 0,
                ('ina', 24): 0
            },
            ('ris', 146): {
                ('ise', 31): 0
            },
            ('rit', 119): {
                ('ite', 174): 0,
                ('ity', 118): 0
            },
            ('ril', 63): {
                ('ily', 88): 0
            },
            ('riz', 56): {
                ('ize', 134): 0
            },
            ('ric', 30): {
                ('ice', 25): 0
            },
            ('rid', 25): {
                ('ide', 49): 0
            },
            ('rif', 24): {
                ('ify', 32): 0
            }
        },
        ('ara', 21): {
            ('rac', 84): {
                ('acy', 60): 0,
                ('ace', 33): 0
            },
            ('rat', 76): {
                ('ate', 451): 0
            },
            ('rag', 56): {
                ('age', 90): 0
            },
            ('rad', 47): {
                ('ade', 36): 0
            }
        }
    },
    ('ref', 153): {
        ('efo', 27): dict()
    },
    ('gen', 150): {
        ('ene', 56): {
            ('nes', 644): {
                ('ese', 33): 0
            },
            ('ner', 118): {
                ('ery', 37): 0
            }
        },
        ('eni', 25): {
            ('nit', 112): {
                ('ite', 200): 0,
                ('ity', 93): 0
            },
            ('nin', 59): {
                ('ine', 54): 0
            },
            ('niz', 33): {
                ('ize', 178): 0
            }
        }
    },
    ('pol', 384): {
        ('oly', 255): dict(),
        ('oli', 35): {
            ('lit', 234): {
                ('ity', 698): 0,
                ('ite', 209): 0
            },
            ('lis', 79): {
                ('ise', 28): 0
            },
            ('lin', 72): {
                ('ine', 206): 0
            },
            ('lid', 36): {
                ('ide', 21): 0
            },
            ('lif', 24): {
                ('ify', 21): 0
            },
            ('liz', 22): {
                ('ize', 209): 0
            }
        },
        ('ola', 22): {
            ('lat', 165): {
                ('ate', 422): 0
            },
            ('lar', 48): {
                ('ary', 106): 0
            },
            ('lan', 27): {
                ('ane', 24): 0
            }
        },
        ('ole', 22): {
            ('len', 60): {
                ('ene', 58): 0
            },
            ('ler', 39): {
                ('ery', 36): 0
            }
        }
    },
    ('lam', 117): {
        ('ame', 33): {
            ('mer', 46): {
                ('ere', 24): 0,
                ('ery', 20): 0
            }
        }
    },
    ('mal', 213): {
        ('ala', 64): {
            ('lac', 67): {
                ('ace', 32): 0
            },
            ('lan', 65): {
                ('ane', 24): 0
            },
            ('lat', 58): {
                ('ate', 422): 0
            },
            ('lar', 31): {
                ('ary', 106): 0
            }
        },
        ('ale', 37): {
            ('len', 90): {
                ('ene', 58): 0
            },
            ('ler', 26): {
                ('ery', 36): 0
            }
        }
    },
    ('rev', 156): {
        ('eve', 76): {
            ('ver', 139): {
                ('ery', 27): 0
            },
            ('vel', 36): {
                ('ely', 168): 0
            }
        },
        ('evi', 44): {
            ('vit', 27): {
                ('ity', 64): 0
            }
        },
        ('evo', 28): dict()
    },
    ('ura', 42): {
        ('ran', 25): {
            ('ani', 91): {
                ('nic', 76): 0
            }
        }
    },
    ('val', 78): {
        ('ale', 28): {
            ('len', 90): {
                ('ene', 58): 0
            },
            ('ler', 26): {
                ('ery', 36): 0
            }
        }
    },
    ('ven', 111): {
        ('ene', 26): {
            ('nes', 644): {
                ('ese', 33): 0
            },
            ('ner', 118): {
                ('ery', 37): 0
            }
        }
    },
    ('lat', 106): {
        ('ati', 39): {
            ('tiv', 517): {
                ('ive', 821): 0
            },
            ('tin', 230): {
                ('ine', 134): 0,
                ('ina', 22): 0
            },
            ('tic', 187): {
                ('ice', 23): 0
            },
            ('tis', 129): {
                ('ise', 25): 0
            },
            ('tiz', 59): {
                ('ize', 100): 0
            },
            ('tit', 52): {
                ('ite', 60): 0
            },
            ('tif', 43): {
                ('ify', 30): 0
            },
            ('til', 25): {
                ('ile', 79): 0,
                ('ily', 37): 0
            }
        },
        ('ate', 27): {
            ('ter', 153): {
                ('ery', 72): 0,
                ('era', 35): 0
            },
            ('tel', 117): {
                ('ely', 112): 0
            },
            ('ten', 74): {
                ('ene', 21): 0
            }
        }
    },
    ('aci', 42): {
        ('cid', 21): {
            ('idi', 49): {
                ('dic', 20): 0
            },
            ('ida', 43): {
                ('dal', 118): 0
            },
            ('ide', 43): {
                ('der', 40): 0,
                ('des', 38): 0,
                ('ded', 20): 0
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它只是复杂对象的一小部分,我发布了如此复杂的示例来表明该对象到底有多复杂,完整的对象从示例的第一层开始可以有多达 15 个嵌套级别,并且第一个还有更多级别键。

让我解释一下这是什么,这是用于基于马尔可夫链的伪词生成中,每个键是一个由三个字母字符串和一个正整数组成的元组,该字符串要么由元音字母,要么由辅音字母组成和一个元音字母或 CVC。

该字符串是一个三字母状态,整数表示该状态的权重/似然/频率,连续级别的每个键都是一个可以跟随前一级别状态的状态,一个状态只能跟随另一个状态当且仅当另一个状态的最后两个字母是第一个状态的开始,数字是从前一个状态转换到下一个状态的可能性。

第一级状态是可以在单词开头找到的状态,第二级状态是在单词中跟随先前第一状态作为第二状态的状态。每个最后一层的值应该是0,表示嵌套结束,在示例中,如果第一个嵌套层的嵌套值为 0,并且每个后续嵌套层的嵌套值加 1,则最后一个嵌套层的嵌套值加 3(长度第一个状态)应该是六(通过遍历树生成的单词的长度应该是)。

一个单词是通过加权随机选择一个状态来生成的,加权随机从它的值中选择一个状态,递归地直到该值为零,然后,取出第一个状态的所有字母,从第二个字母开始的第三个字母说明并连接字母。

例如,如果选择是 ('uni', 'nin', 'ine', 'ned'),则要采用的块是'uni', 'n', 'e', 'd',生成的单词是'unined'

现在我有三个问题,第一个问题是字典没有排序,这是最容易解决的。第二个是字典有空的嵌套字典,这些字典意味着分支过早终止,因为分支不能“合法”增长,这些分支无效,我想从最后一层到第一层递归地切断无效分支level(从最后一级到第一级,如果值字典为空,则递归地向后弹出键,直到值不再为空),这个有点困难。

最困难的部分是,有很多分支只有一个子分支,我需要递归地将这些子分支与其父分支合并,从最后一层向后到第一层。

简而言之,我需要它变成这样:

{
    ('acid', 42): {
        ('idal', 43): 0,
        ('ide', 43): {
            ('ded', 20): 0,
            ('der', 40): 0,
            ('des', 38): 0
        },
        ('idic', 49): 0
    },
    ('dete', 122): {
        ('tene', 65): 0,
        ('ter', 212): {
            ('era', 35): 0,
            ('ery', 72): 0
        }
    },
    ('gen', 150): {
        ('ene', 56): {
            ('nery', 118): 0,
            ('nese', 644): 0
        },
        ('eni', 25): {
            ('nine', 59): 0,
            ('nit', 112): {
                ('ite', 200): 0,
                ('ity', 93): 0
            },
            ('nize', 33): 0
        }
    },
    ('iron', 30): {
        ('onal', 44): 0,
        ('one', 47): {
            ('ned', 86): 0,
            ('ner', 85): 0,
            ('nes', 26): 0,
            ('net', 20): 0
        },
        ('onic', 94): 0
    },
    ('lamer', 117): {
        ('ere', 24): 0,
        ('ery', 20): 0
    },
    ('lat', 106): {
        ('ate', 27): {
            ('tely', 117): 0,
            ('tene', 74): 0,
            ('ter', 153): {
                ('era', 35): 0,
                ('ery', 72): 0
            }
        },
        ('ati', 39): {
            ('tice', 187): 0,
            ('tify', 43): 0,
            ('til', 25): {
                ('ile', 79): 0,
                ('ily', 37): 0
            },
            ('tin', 230): {
                ('ina', 22): 0,
                ('ine', 134): 0
            },
            ('tise', 129): 0,
            ('tite', 52): 0,
            ('tive', 517): 0,
            ('tize', 59): 0
        }
    },
    ('mal', 213): {
        ('ala', 64): {
            ('lace', 67): 0,
            ('lane', 65): 0,
            ('lary', 31): 0,
            ('late', 58): 0
        },
        ('ale', 37): {
            ('lene', 90): 0,
            ('lery', 26): 0
        }
    },
    ('mar', 286): {
        ('ara', 21): {
            ('rac', 84): {
                ('ace', 33): 0,
                ('acy', 60): 0
            },
            ('rade', 47): 0,
            ('rage', 56): 0,
            ('rate', 76): 0
        },
        ('ari', 30): {
            ('rice', 30): 0,
            ('ride', 25): 0,
            ('rify', 24): 0,
            ('rily', 63): 0,
            ('rin', 156): {
                ('ina', 24): 0,
                ('ine', 168): 0
            },
            ('rise', 146): 0,
            ('rit', 119): {
                ('ite', 174): 0,
                ('ity', 118): 0
            },
            ('rize', 56): 0
        }
    },
    ('nati', 66): {
        ('tice', 187): 0,
        ('tify', 43): 0,
        ('til', 25): {
            ('ile', 79): 0,
            ('ily', 37): 0
        },
        ('tin', 230): {
            ('ina', 22): 0,
            ('ine', 134): 0
        },
        ('tise', 129): 0,
        ('tite', 52): 0,
        ('tive', 517): 0,
        ('tize', 59): 0
    },
    ('pol', 384): {
        ('ola', 22): {
            ('lane', 27): 0,
            ('lary', 48): 0,
            ('late', 165): 0
        },
        ('ole', 22): {
            ('lene', 60): 0,
            ('lery', 39): 0
        },
        ('oli', 35): {
            ('lide', 36): 0,
            ('lify', 24): 0,
            ('line', 72): 0,
            ('lise', 79): 0,
            ('lit', 234): {
                ('ite', 209): 0,
                ('ity', 698): 0
            },
            ('lize', 22): 0
        }
    },
    ('rem', 125): {
        ('emer', 26): {
            ('ere', 24): 0,
            ('ery', 20): 0
        },
        ('emi', 32): {
            ('mine', 109): 0,
            ('mit', 58): {
                ('ite', 64): 0,
                ('ity', 45): 0
            }
        },
        ('emo', 35): {
            ('mony', 133): 0,
            ('more', 62): 0,
            ('mose', 29): 0,
            ('mote', 35): 0
        }
    },
    ('rev', 156): {
        ('eve', 76): {
            ('vely', 36): 0,
            ('very', 139): 0
        },
        ('evity', 44): 0
    },
    ('uni', 217): {
        ('nimal', 31): 0,
        ('nine', 62): {
            ('ned', 88): 0,
            ('ner', 74): 0,
            ('net', 25): 0
        },
        ('niver', 25): 0
    },
    ('uranic', 42): 0,
    ('vale', 78): {
        ('lene', 90): 0,
        ('lery', 26): 0
    },
    ('vene', 111): {
        ('nery', 118): 0,
        ('nese', 644): 0
    }
}
Run Code Online (Sandbox Code Playgroud)

我是这样做的:

def merge(obj):
    for k, v in list(obj.items()):
        if isinstance(v, dict):
            merge(v)
            if len(v) == 1:
                a, b = k
                k1, v1 = list(obj.pop(k).items())[0]
                key = (a + k1[0][2:], b)
                obj[key] = v1

def pop_empty(obj):
    for k, v in list(obj.items()):
        if isinstance(v, dict):
            pop_empty(v)
            if not v:
                obj.pop(k)


def nested_sort(dic):
    d = dict()
    for k, v in sorted(dic.items()):
        if isinstance(v, dict):
            d[k] = nested_sort(v)
        else:
            d[k] = v
    return d

pop_empty(example)
merge(example)
nested_sort(example)
Run Code Online (Sandbox Code Playgroud)

我需要处理一个比这复杂得多的极其复杂的对象,有什么更有效的方法来做到这一点?

该对象有许多重复的元素和重复的嵌套字典,一般来说,重复非常重,记忆化是一个巨大的帮助,但是其中两个函数不返回任何值,而一个函数返回一个值,尝试使用 lru_cache 包装它会引发unhashable type dict,任何人都可以使用记忆法重新实现相同的想法吗?

Leo*_*ark 4

通过结合这三个过程,我的速度提高了约 25%。

def merge(obj, /):
    result = {}
    for key, val in sorted(obj.items()):
        if isinstance(val, dict):
            val = merge(val)
            if not val:
                continue
            if len(val) == 1:
                k1, val = next(iter(val.items()))
                key = (key[0] + k1[0][2:], key[1])
        result[key] = val
    return result
Run Code Online (Sandbox Code Playgroud)

我不知道还有多少可能。