使用递归函数删除嵌套字典中的空dicts

时间:2015-11-04 18:26:50

标签: python python-2.7 python-3.x

我试图从嵌套词典中删除非值。我的第一次努力工作正常,但不幸的是,指向现在空的dicts的键仍然存在。

所以,如果我这样做:

pass1 = stripper(my_dict)
return stripper(pass1)

这有效,但我认为可能有更优雅的嵌套解决方案吗?

def stripper(self, data):
    if isinstance(data, dict):
        d = ({k: stripper(v) for k, v in data.items()
             if v not in [u'', None]})
        if d:
            return d
    else:
        return data

编辑:

失败的示例,下面的dict返回为{'foo': 'bar', 'bar': None}

{
    'foo': 'bar',
    'bar': {
        'foo': None,
        'one': None
    }
}

3 个答案:

答案 0 :(得分:2)

字典理解当然简洁,但如果你把它扩展出来,解决方案就会变得更加明显:

def stripper(self, data):
    new_data = {}
    for k, v in data.items():
        if isinstance(v, dict):
            v = stripper(v)
        if not v in (u'', None, {}):
            new_data[k] = v
    return new_data

答案 1 :(得分:0)

将接受的答案扩展为包括可能是列表元素的对象:

def strip_empties_from_list(data):
    new_data = []
    for v in data:
        if isinstance(v, dict):
            v = strip_empties_from_dict(v)
        elif isinstance(v, list):
            v = strip_empties_from_list(v)
        if v not in (None, str(), list(), dict(),):
            new_data.append(v)
    return new_data


def strip_empties_from_dict(data):
    new_data = {}
    for k, v in data.items():
        if isinstance(v, dict):
            v = strip_empties_from_dict(v)
        elif isinstance(v, list):
            v = strip_empties_from_list(v)
        if v not in (None, str(), list(), dict(),):
            new_data[k] = v
    return new_data

要使用:

data = {
  'None': None,
  'empty_list': [],
  'empty_dict': {},
  'empty_string': '',
  'list_with_empties': ['', {}, [], None, {'more_empties': '', 'and_even_more': [''], 'one_thing_i_care_about': 'hi'}]
}
stripped_data = strip_empties_from_dict(data)
print(stripped_data)

答案 2 :(得分:0)

@Oliver 的答案是正确的,但是进行一些边缘情况检查不会有什么坏处,给您:(由于队列已满,无法编辑 Oliver 的答案)

    def dictionary_stripper(data):
        new_data = {}
        
        # Only iterate if the given dict is not None
        if data:
            for k, v in data.items():
                if isinstance(v, dict):
                    v = CampaignAdminUtils.dictionary_stripper(v)
                
                # ideally it should be not in, second you can also add a empty list if required
                if v not in ("", None, {}, []):
                    new_data[k] = v
            
            # Only if you want the root dict to be None if empty
            if new_data == {}:
                return None
            return new_data
        return None