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

이 코드는 작동하지만 매우 우아하지는 않으며 더 나은 솔루션을 코딩 할 수 있다고 확신합니다. 이미 DICT의 모든 요소를 ​​통해 루프를 필요로하기 때문에, 나는

+0

흠 나는 그것이 우아한 발견을! –

+3

나는 그것이 나쁜 코드가 아니라고 생각한다; 중첩 된 사전에 대해 재귀하는 중요한 비트가 있습니다. 아마도 isinstance (spam, collections.MutableMapping)을 더 다형 적으로 검사해야합니다. – katrielalex

답변

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': ' 그리고 사전에서 모든 입력란을 삭제하십시오. ( – fasouto

+1

위의 코드를 업데이트했습니다.) 사전을 반환하지 않았습니다. (예 : 'asdas identyfier', 'name': 'collection' 이 함수는 사전을 수정하지 않으므로 전달 된 동일한 사전을 인쇄 할 수 있습니다. 코드를 업데이트하여 사전을 반환하도록했습니다. –

+1

tbh 당신의 fisrt 버전이 더 좋았던 것 같아요. 원래는 이미 업데이트 된 키가 있고 이미 존재하는 어떤 것을 반환하기 위해 반환 값을 낭비하지 않았기 때문입니다. 앞으로는 기존의 호출 코드를 변경하지 않고 제거 된 값의 수를 예를 들어 반환합니다. – laurent

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 : 우리가 이것을 뒤집을 수있는 방법이 있습니까? 특정 키를 유지하고 목록에없는 나머지를 삭제한다는 의미입니까? –

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에서 훨씬 더 큰 개체로 작업하는 것을 포함하여 더 많은 예제가 있습니다.

순수 파이썬이므로 모든 곳에서 작동하며 파이썬 2.7 및 3.3+에서 완전히 테스트됩니다. 무엇보다도, 나는 이와 같은 정확한 경우를 위해 그것을 썼습니다. 그래서 당신이 처리하지 않는 케이스를 발견한다면, 버그를 수정해서 right here을 고칠 수 있습니다.

+0

깔끔한! :) 고맙습니다. – darkless

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} 
관련 문제