代码之家  ›  专栏  ›  技术社区  ›  David542

删除嵌套字典中的所有空键(通过yield)

  •  1
  • David542  · 技术社区  · 6 年前

    我有以下函数可以删除值为空或以下划线开头的键。它适用于非嵌套字典:

    def _remove_missing_and_underscored_keys(d):
        if not d: return d
        for key in d.keys():
            if not d.get(key):
                del d[key]
            elif key.startswith('_'):
                del d[key]
    
        return d
    
    d = {"Name": "David",
        "_Age": 50,
        "Numbers": [1,2,3,4,5],
        "Height": ""
    }
    
    >>> _remove_missing_and_underscored_keys(d)
    {'Name': 'David', 'Numbers': [1, 2, 3, 4, 5]}
    

    但是,我想创建上面的内容,以便它也可以删除嵌套项。我相信我需要使用一个yield语句来实现这一点,但是我没有幸运地正确实现它。下面是我想要它做什么的一个例子:

    d = {
        "PlatformID": "B00EU7XL9Q",
        "Platform": "Amazon",
        "Type": "Collection",
        "Products": {
            "UK": {
                "URL": "http://www.amazon.co.uk/dp/B00EU7XL9Q",
                "Rating": None,
                "_IsAudited": True,
                "Offers": {
                    "HDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    },
                    "SDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    }
                }
            }
        }
    }
    

    >>> _remove_missing_and_underscored_keys(d)
    {
        "PlatformID": "B00EU7XL9Q",
        "Platform": "Amazon",
        "Type": "Collection",
        "Products": {
            "UK": {
                "URL": "http://www.amazon.co.uk/dp/B00EU7XL9Q",
                "Offers": {
                    "HDBUY": {
                        "Currency": "GBP",
                        "Cost": "14.99",
                    },
                    "SDBUY": {
                        "Currency": "GBP",
                        "Cost": "14.99",
                    }
                }
            }
        }
    }
    

    换句话说,它将在dict的所有嵌套级别上执行上述操作。

    4 回复  |  直到 6 年前
        1
  •  1
  •   E.Serra    6 年前
    def _remove_missing_and_underscored_keys(d):
        if not d: return d
        for key in d.keys():
            if not d.get(key):
                del d[key]
            elif key.startswith('_'):
                del d[key]
            elif type(d[key]) == dict:
                d[key] = _remove_missing_and_underscored_keys(d[key])
    
        return d
    
        2
  •  1
  •   Skam    6 年前

    我想你是想说,你需要用递归来解决这个问题。我认为使用发电机并不能完全解决你的问题。 另一个警告是,不应该迭代正在更改的变量。这就是我创建副本的原因 _d 修改并返回它,并遍历原始结构。

    import pprint
    
    def _remove_missing_and_underscored_keys(d):
        if not d: return d
        _d = d.copy()
        for key in _d.keys():
            if not _d.get(key):
                del d[key]
            elif key.startswith('_'):
                del d[key]
            elif isinstance(_d[key], dict):
                _remove_missing_and_underscored_keys(_d[key])
        return _d
    
    _d = {
        "PlatformID": "B00EU7XL9Q",
        "Platform": "Amazon",
        "Type": "Collection",
        "Products": {
            "UK": {
                "URL": "http://www.amazon.co.uk/dp/B00EU7XL9Q",
                "Rating": None,
                "_IsAudited": True,
                "Offers": {
                    "HDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    },
                    "SDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    }
                }
            }
        }
    }
    foo = _remove_missing_and_underscored_keys(_d)
    pprint.pprint(foo)
    

    输出:

     {'Platform': 'Amazon',
     'PlatformID': 'B00EU7XL9Q',
     'Products': {'UK': {'Offers': {'HDBUY': {'Cost': '14.99', 'Currency': 'GBP'},
                                    'SDBUY': {'Cost': '14.99', 'Currency': 'GBP'}},
                         'URL': 'http://www.amazon.co.uk/dp/B00EU7XL9Q'}},
     'Type': 'Collection'}
    
        3
  •  1
  •   Tushar    6 年前

    只是递归。

    再添加一个检查,看看主dict中的值是否是dict,并对其调用相同的函数。

    # your code goes here
    def _remove_missing_and_underscored_keys(d):
        if not d: return d
        for key in d.keys():
            if not d.get(key):
                del d[key]
            elif key.startswith('_'):
                del d[key]
            elif type(d[key]) is dict:
                #print("key '{}' stores a dict '{}', need to cleanup recursively".format(key, d[key]))
                d[key] = _remove_missing_and_underscored_keys(d[key])
                # Keep below check if you want to treat empty dict as `empty` as well
                if d[key] == None or d[key] == {}:
                    del d[key]
    
        return d
    
    d = {
        "PlatformID": "B00EU7XL9Q",
        "Platform": "Amazon",
        "Type": "Collection",
        "Products": {
            "UK": {
                "URL": "http://www.amazon.co.uk/dp/B00EU7XL9Q",
                "Rating": None,
                "_IsAudited": True,
                "Offers": {
                    "HDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    },
                    "SDBUY": {
                        "Currency": "GBP",
                        "FutureReleaseStartDate": None,
                        "Cost": "14.99",
                        "IsFutureRelease": False
                    },
                    "x" : {
                        "y":None
                    }
                }
            }
        }
    }
    
    e = _remove_missing_and_underscored_keys(d)
    print(e)
    

    见效: https://ideone.com/5xDDZl

    上面的代码还处理存储在任何键上的空dict,或者在递归地清除后变为空的任何dict。如果需要,您可以取消该支票。

        4
  •  1
  •   Ajax1234    6 年前

    您可以使用递归和字典理解:

    d = {'PlatformID': 'B00EU7XL9Q', 'Platform': 'Amazon', 'Type': 'Collection', 'Products': {'UK': {'URL': 'http://www.amazon.co.uk/dp/B00EU7XL9Q', 'Rating': None, '_IsAudited': True, 'Offers': {'HDBUY': {'Currency': 'GBP', 'FutureReleaseStartDate': None, 'Cost': '14.99', 'IsFutureRelease': False}, 'SDBUY': {'Currency': 'GBP', 'FutureReleaseStartDate': None, 'Cost': '14.99', 'IsFutureRelease': False}}}}}
    def _del(_d):
      return {a:_del(b) if isinstance(b, dict) else b for a, b in _d.items() if b and not a.startswith('_')}
    

    import json
    print(json.dumps(_del(d), indent=4))
    

    输出:

    {
     "PlatformID": "B00EU7XL9Q",
     "Platform": "Amazon",
     "Type": "Collection",
     "Products": {
        "UK": {
            "URL": "http://www.amazon.co.uk/dp/B00EU7XL9Q",
            "Offers": {
                "HDBUY": {
                    "Currency": "GBP",
                    "Cost": "14.99"
                },
                "SDBUY": {
                    "Currency": "GBP",
                    "Cost": "14.99"
                }
            }
         }
       }
    }