从嵌套字典递归删除None值或键

时间:2019-11-13 12:36:09

标签: python python-3.x list dictionary

问题:

如何遍历字典并删除其中的ourtestuser@gmail.com键或值?

这是我尝试过的:

代码:

None

输入:

import copy


def _ignore(data):
    copied_data = copy.deepcopy(data)

    print('-------------------------')
    print(f'copied_data: {copied_data}')
    print('-------------------------')

    if isinstance(copied_data, list):
        print(f'item is instance of list: {copied_data}')

        for idx, item in enumerate(data):
            if isinstance(item, list):
                return _ignore(item)

            elif isinstance(item, dict):
                return _ignore(item)

            elif item is None:
                del copied_data[idx]

    elif isinstance(copied_data, dict):
        print(f'item is instance of dict: {copied_data}')

        for key, item in data.items():
            if isinstance(item, list):
                return _ignore(item)

            elif isinstance(item, dict):
                return _ignore(item)

            elif item is None:
                del copied_data[key]

    return copied_data


if __name__ == '__main__':
    data = {'key1': None, 'key2': {'k1': None, 'k2': 2}, 'key3': [None, 1, 2, 3, 4]}

    print(f'output: {_ignore(data=data)}')

输出:

{'key1': None, 'key2': {'k1': None, 'k2': 2}, 'key3': [None, 1, 2, 3, 4]}
  

请紧记,该代码还应删除嵌套------------------------- copied_data: {'key1': None, 'key2': {'k1': None, 'k2': 2}, 'key3': [None, 1, 2, 3, 4]} ------------------------- item is instance of dict: {'key1': None, 'key2': {'k1': None, 'k2': 2}, 'key3': [None, 1, 2, 3, 4]} ------------------------- copied_data: {'k1': None, 'k2': 2} ------------------------- item is instance of dict: {'k1': None, 'k2': 2} output: {'k2': 2} 或嵌套None中的list个值,而我们不能从{ {1}},我们正在对其进行迭代。

更新: 该代码应支持嵌套的dictdict

这是另一个输入示例:

dict

谢谢。

4 个答案:

答案 0 :(得分:1)

您可以递归检查并返回key, value对,然后像这样从中创建一个新的dict

$ cat rmnone.py
data = {'key1': None, 'key2': {'k1': {'k3': [None, 1, 23], 'k4': None}, 'k2': 2},
        'key3': [{'key1': None, 'key2': [None, 1, 2, 3], 'key3': {'k1': 1}}, 1, 2, 3, 4]}

def func(data):
    for key, val in data.items():
        if val is not None:
            if isinstance(val, list):
                tmp = []
                for v in val:
                    if isinstance(v, dict):
                        for k,v in func(v):
                            tmp.append({k:v})
                    elif v is not None:
                        tmp.append(v)
                yield (key, tmp)
            if isinstance(val, tuple):
                tmp = []
                for v in val:
                    if isinstance(v, dict):
                        for k,v in func(v):
                            tmp.append({k:v})
                    elif v is not None:
                        tmp.append(v)
                yield (key, tmp)
            elif isinstance(val, dict):
                    tmp = {}
                    for k,v in func(val):
                        tmp.update({k:v})
                    yield key, tmp
            elif not isinstance(val, (tuple, dict, list)):
                yield key,val

d = {k:v for k,v in func(data)}
print(d)

输出:

$ python3 rmnone.py
{'key2': {'k1': {'k3': [1, 23]}, 'k2': 2}, 'key3': [{'key2': [1, 2, 3]}, {'key3': {'k1': 1}}, 1, 2, 3, 4]}

答案 1 :(得分:1)

这里是创建新对象的一种方法。

def removed_none(obj):
    t = type(obj)
    if issubclass(t, (tuple, list, set)):
        obj = t(removed_none(a) for a in obj if a is not None)
    elif issubclass(t, dict):
        obj = {k: removed_none(v) for k, v in obj.items()
               if k is not None and v is not None}
    return obj

data = {'key1': None, 'key2': {'k1': None, 'k2': {1: 2, 3: None}},
        'key3': [None, [1, None, 0], 2, 3, 4]}
print(f'output: {removed_none(data)}')
# output: {'key2': {'k2': {1: 2}}, 'key3': [[1, 0], 2, 3, 4]}

如果要在适当位置修改现有对象,则这里有一个不同的功能(remove_none而不是removed_none)。请注意,这不能用于修改包含None值的元组,因为它们是不可变的。

def remove_none(obj):
    if isinstance(obj, list):
        for i in range(len(obj) - 1, -1, -1):
            if obj[i] is None:
                del obj[i]
            else:
                remove_none(obj[i])
    elif isinstance(obj, set):
        obj.discard(None)
        for elem in obj:
            remove_none(elem)
    elif isinstance(obj, dict):
        for k, v in list(obj.items()):
            if k is None or v is None:
                del obj[k]
            else:
                remove_none(v)

data = {'key1': None, 'key2': {'k1': None, 'k2': {1: 2, 3: None}},
        'key3': [None, [1, None, 0], 2, 3, 4]}
remove_none(data)
print(f'output: {data}')
# output: {'key2': {'k2': {1: 2}}, 'key3': [[1, 0], 2, 3, 4]}

答案 2 :(得分:1)

您没有按照自己的意愿去做,因为据我所知,您仅删除了None个值。该命令:

{'key1': None, 'key2': {'k1': None, 'k2': 2}, 'key3': [None, 1, 2, 3, 4]}

仅具有None值,没有键。我要在这里坚持键和值的Python定义。 None键如下:

{None: "value"}

但是,您可以轻松地执行以下操作:

def recursive_filter(item, *forbidden):
    if isinstance(item, list):
        return [recursive_filter(entry, *forbidden) for entry in item if entry not in forbidden]
    if isinstance(item, dict):
        result = {}
        for key, value in item.items():
            value = recursive_filter(value, *forbidden)
            if key not in forbidden and value not in forbidden:
                result[key] = value
        return result
    return item

您可以像这样使用:

clean = recursive_filter(dirty, None)

或者,如果您想过滤出更多内容:

clean = recursive_filter(dirty, *iterable_of_forbidden_things)
clean = recursive_filter(dirty, None, other_forbidden_thing)

如果您真的只在乎值,那么就可以删除对键的检查。

答案 3 :(得分:0)

这基本上已经完成了here,并且也以稍微修改的形式解决了该问题:

d = {'key1': None, 
     'key2': {'k1': None, 'k2': 2}, 
     'key3': [None, 1, 2, 3, 4],
     None: 42}    

def scrub_none(node):
    if isinstance(node, dict):
        for k in list(node.keys()):
            if node[k] is None or k is None:
                del node[k]
            else:
                scrub_none(node[k])
    elif isinstance(node, list):
        for i in reversed(range(len(node))):
            if node[i] is None:
                del node[i]
            else:
                scrub_none(node[i])
    else:
        pass

scrub_none(d)   
print(d)
# {'key2': {'k2': 2}, 'key3': [1, 2, 3, 4]}

注释#1:就地修改输入dict

注释#2:还会删除None键(如果存在)