2010-08-04 144 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}