python生成器经典应用——The Flat Dictonary(扁平字典)问题

题目来源:The Flat Dictionary

一.题目

You are given a dictionary where the keys are strings and the values are strings or dictionaries. The goal is flatten the dictionary, but save the structures in the keys. The result should be the a dictionary without the nested dictionaries. The keys should contain paths that contain the parent keys from the original dictionary. The keys in the path are separated by a “/”. If a value is an empty dictionary, then it should be replaced by an empty string (""). Let’s look at an example:

大致题意

对于一个字典,其键为字符串,其值可能为字符串有可能是一个字典。我们的目标是展平这种字典,但是需要保存键中的结构。结果字典应当是一个不包含嵌套字典的字典(称为扁平字典)。扁平字典的键应当包含原始字典的父键的理解。路径中的键使用"/“分隔。如果原始字典中某个原始的值为空字典,应该用空字符串”"代替它。

题目示例

{
    "name": {
        "first": "One",
        "last": "Drone"
    },
    "job": "scout",
    "recent": {},
    "additional": {
        "place": {
            "zone": "1",
            "cell": "2"}
    }
}

The result will be:

{"name/first": "One",           #one parent
 "name/last": "Drone",
 "job": "scout",                #root key
 "recent": "",                  #empty dict
 "additional/place/zone": "1",  #third level
 "additional/place/cell": "2"}

二.解题大致思路

  • 对于本题,由于要消除嵌套字典,利用递归很方便。
  • 由于要保存原始字典中的键结构,因此添加了变量用来保存在不断往深度递归过程中的各级键(用"分隔"),使之成为一个“路径”。
  • 递归过程若当前元素是一个字典则遍历其中所有键值对,在遍历过程中需要添加当前遍历的键值对的键到“路径”中去,然后继续对键值对中的值继续进行递归,直到当前元素不再是一个字典位置,这时yield值和“路径”。

:若对生成器不熟悉可以看一下博主的这篇文章:关于迭代器和生成器,你该了解这些,作为一名python爱好者,生成器绝对一门利器。

三.代码

def disdepth(dit,pre):
    """
    消除嵌套的生成器
    dit:当前元素,可能为字典,有可能是字典中的一个键值对
    pre:父路径
    """
    if type(dit) == dict:#dit是字典
      for key,value in dit.items():
        if value == {}:#键值对中的值为空字典用""代替
          value = ""
        if pre and pre[-1]!='/':#用'/'分隔路径
          pre += '/'
        yield from disdepth(value,pre + key)
    else:#dit为一个值,pre到它位置的父键构成的路径
        yield pre,dit 

def flatten(dictionary):
    out = {}
    for key,value in disdepth(dictionary,''):
        out[key] = value
    return out


if __name__ == '__main__':
    test_input = {"key": {"deeper": {"more": {"enough": "value"}}}}
    print(' Input: {}'.format(test_input))
    print('Output: {}'.format(flatten(test_input)))

    #These "asserts" using only for self-checking and not necessary for auto-testing
    assert flatten({"key": "value"}) == {"key": "value"}, "Simple"
    assert flatten(
        {"key": {"deeper": {"more": {"enough": "value"}}}}
    ) == {"key/deeper/more/enough": "value"}, "Nested"
    assert flatten({"empty": {}}) == {"empty": ""}, "Empty value"
    assert flatten({"name": {
                        "first": "One",
                        "last": "Drone"},
                    "job": "scout",
                    "recent": {},
                    "additional": {
                        "place": {
                            "zone": "1",
                            "cell": "2"}}}
    ) == {"name/first": "One",
          "name/last": "Drone",
          "job": "scout",
          "recent": "",
          "additional/place/zone": "1",
          "additional/place/cell": "2"}
    print('You all set. Click "Check" now!')

若有什么问题欢迎指出,倘若觉得不错希望多多支持!!!

你可能感兴趣的:(python)