2010-08-04 12 views
9

Musiałem usunąć niektóre pola ze słownika, klucze tych pól znajdują się na liście. Więc piszę tę funkcję:Elegancki sposób usuwania pól ze słowników zagnieżdżonych

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 

Ten kod działa, ale nie jest zbyt elegancki i jestem pewien, że możesz napisać lepsze rozwiązanie.

+0

hmmm znajdę to elegancki! –

+3

Myślę, że to nie jest zły kod; masz ważny bit, który jest rekursywny w przypadku zagnieżdżonych słowników. Powinieneś prawdopodobnie sprawdzić, czy 'isinstance (spam, collections.MutableMapping)' jest bardziej polimorficzny. – katrielalex

Odpowiedz

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

Przepraszamy, ale ten kod nie działa zgodnie z oczekiwaniami. Próbuję wykonać: print delete_keys_from_dict ({'code': 'sdasda', 'tag.dbmko8e8': {'id': 'casas', 'name': ' asdas identyfier '},' name ':' collection '}, ["id"]) I usuń wszystkie pola ze słownika :( – fasouto

+1

Nie zwróciłem słownika (zaktualizowałem powyższy kod). Otrzymujesz komunikat "Brak", ponieważ wartość nie została zwrócona, ponieważ ta funkcja nie modyfikuje słownika, możesz po prostu wydrukować ten sam słownik, który przekazałeś. Zaktualizowałem kod, aby zwrócić także dict. –

+1

tbh Myślę, że twoja wersja fisrt była lepsza, nie zwracając słownika, ponieważ jak powiedziałeś, oryginał będzie miał już zaktualizowane klucze i nie "marnujesz" wartości zwracanej, aby zwrócić coś już istniejącego, a metoda może być w przyszłości, aby powrócić na przykład liczbę usuniętych wartości bez zmian już istniejącego kodu wywołującego. – laurent

3

Skoro już trzeba pętli każdy element w dict, będę trzymać się z jednej pętli i po prostu upewnij się, aby użyć zestawu dla patrząc klucze do usunięcia

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: czy istnieje sposób, żeby to odwrócić? Mam na myśli tylko utrzymywanie określonych kluczy i usuwanie reszty, których nie ma na liście? –

6

Ponieważ pytanie wymagało eleganckiego sposobu, przekażę moje rozwiązanie ogólnego przeznaczenia do splatania struktur zagnieżdżonych. Po pierwsze, należy zainstalować boltons utility package z pip install boltons, a następnie:

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'} 

W skrócie, the remap utility jest w pełni funkcjonalny, ale zwięzły podejście do obsługi struktur danych rzeczywistych, które często są zagnieżdżone, a nawet może zawierać cykle i specjalne pojemniki.

This page ma wiele innych przykładów, w tym te, które pracują z większymi obiektami z API Githuba.

Jest to czysty Python, więc działa wszędzie i jest w pełni przetestowany w Pythonie 2.7 i 3.3+. Najlepszy ze wszystkich, napisałem to dla dokładnie takich przypadków, więc jeśli znajdziesz skrzynkę, której nie obsługuje, możesz mnie zaalarmować, aby to naprawić right here.

+0

Schludny! :) Dziękuję Ci. – darkless

0

Korzystanie niesamowite kod z this posta i dodać niewielką stwierdzenie:

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

myślę, że jest bardziej elegancki następujący:

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} 
Powiązane problemy