2010-08-04 145 views
9

我不得不从字典中删除一些字段,这些字段的键位于列表中。所以,我写这篇文章的功能:从嵌套字典中删除字段的优雅方法

def delete_keys_from_dict(dict_del, lst_keys): 
    """ 
    Delete the keys present in the lst_keys from the dictionary. 
    Loops recursively over nested dictionaries. 
    """ 
    dict_foo = dict_del.copy()#Used as iterator to avoid the 'DictionaryHasChanged' error 
    for field in dict_foo.keys(): 
     if field in lst_keys: 
      del dict_del[field] 
     if type(dict_foo[field]) == dict: 
      delete_keys_from_dict(dict_del[field], lst_keys) 
    return dict_del 

此代码的工作,但它不是很优雅,我敢肯定,你可以编写一个更好的解决方案。

+0

嗯我觉得很优雅! – 2010-08-04 13:04:22

+3

我认为这不是错误的代码;你已经获得了嵌套字典递归的重要位。你应该检查'isinstance(spam,collections.MutableMapping)'是否更多态。 – katrielalex 2010-08-04 13:04:30

回答

15
def delete_keys_from_dict(dict_del, lst_keys): 
    for k in lst_keys: 
     try: 
      del dict_del[k] 
     except KeyError: 
      pass 
    for v in dict_del.values(): 
     if isinstance(v, dict): 
      delete_keys_from_dict(v, lst_keys) 

    return dict_del 
+1

对不起,但这段代码不能按预期工作我试着去做: print delete_keys_from_dict({'code':'sdasda','tag.dbmko8e8':{'id':'casas','name':' asdas identyfier'},'name':'collection'},[“id”]) 并删除字典中的所有字段:( – fasouto 2010-08-04 13:22:19

+1

我没有返回字典(我更新了上面的代码)。因为这个值没有被返回,所以你得到了“None”,因为这个函数不修改字典,所以你可以简单地打印你传入的字典。我更新了代码,所以它也返回字典。 – 2010-08-04 13:30:25

+1

tbh我认为你的fisrt版本更好,没有返回字典,因为正如你所说,原来已经有更新的键,你不是“浪费”返回值返回已存在的东西,方法可能是mo在将来返回例如返回的值的数量而不改变已存在的调用代码。 – laurent 2010-08-04 13:47:22

3

既然你已经通过在字典每个元素都需要循环,我会用一个循环坚持,只是确保使用一组用于查找键删除

def delete_keys_from_dict(dict_del, the_keys): 
    """ 
    Delete the keys present in the lst_keys from the dictionary. 
    Loops recursively over nested dictionaries. 
    """ 
    # make sure the_keys is a set to get O(1) lookups 
    if type(the_keys) is not set: 
     the_keys = set(the_keys) 
    for k,v in dict_del.items(): 
     if k in the_keys: 
      del dict_del[k] 
     if isinstance(v, dict): 
      delete_keys_from_dict(v, the_keys) 
    return dict_del 
+0

@Ned Batchelder:有没有一种方法可以扭转这种情况?我的意思是只保留特定的键并删除不在列表中的其余部分? – 2018-02-15 15:28:31

6

由于这个问题需要一个优雅的方式,我将提交我的通用解决方案来讨论嵌套结构。首先,安装boltons utility packagepip install boltons,则:

from boltons.iterutils import remap 

data = {'one': 'remains', 'this': 'goes', 'of': 'course'} 
bad_keys = set(['this', 'is', 'a', 'list', 'of', 'keys']) 

drop_keys = lambda path, key, value: key not in bad_keys 
clean = remap(data, visit=drop_keys) 
print(clean) 

# Output: 
{'one': 'remains'} 

总之,the remap utility是一个全功能的,但简洁的方法来处理这往往是嵌套在现实世界中的数据结构,甚至可以包含周期,特殊容器。

This page有更多的例子,包括从Github的API中处理更大的对象的例子。

它是纯Python,因此它可以在任何地方工作,并且已经在Python 2.7和3.3+中进行了全面测试。最重要的是,我为这样的案例编写了它,所以如果你发现它无法处理的情况,你可以修复我的错误right here

+0

整洁! :) 谢谢。 – darkless 2016-08-03 12:15:22

0

this后使用真棒代码并添加一个小声明:

def remove_fields(self, d, list_of_keys_to_remove): 
     if not isinstance(d, (dict, list)): 
      return d 
     if isinstance(d, list): 
      return [v for v in (self.remove_fields(v, list_of_keys_to_remove) for v in d) if v] 
     return {k: v for k, v in ((k, self.remove_fields(v, list_of_keys_to_remove)) for k, v in d.items()) if k not in list_of_keys_to_remove} 
0

我认为下面是更优雅:

def delete_keys_from_dict(dict_del, lst_keys): 
    if not isinstance(dict_del, dict): 
     return dict_del 
    return {key:value for key,value in ((key, delete_keys_from_dict(value)) for key,value in dict_del.items()) if key not in lst_keys}