2013-02-11 14 views
5

Mam słownika jako:Python: elegancki sposób, aby usunąć pustych list ze słownika Pythona

default = {'a': ['alpha'], 'b': ['beta','gamma'], 'g': []} 

pragnę wyeliminować puste wartości, jak:

default = {'a': ['alpha'], 'b': ['beta','gamma']} 

napisałem funkcję (po przykładem znaleźć w internecie)

def remove_empty_keys(d): 
    for k in d.keys(): 
     try: 
      if len(d[k]) < 1: 
       del[k] 
     except: 
      pass 
     return(d) 

mam następujące pytania:

1- nie znalazłem błąd, dlaczego to zawsze wraca po -

remove_empty_keys(default) 
{'a': ['alpha'], 'b': ['beta'], 'g': []} 

2- Czy istnieje funkcja wbudowana w celu wyeliminowania/usuwać/null Brak/puste wartości ze słownika Pythona bez tworzenia kopia oryginalnego słownika?

+1

Twoje pytanie wydaje się mieszać ideę "Brak" z pustymi listami. Utrudnia to rozumienie. –

+0

Być może lepszym sposobem na powiedzenie byłoby "Czy istnieje funkcja eliminująca wartości fałszerstwa ze słownika" – mgilson

+0

Twoja klauzula "wypróbuj ... z wyjątkiem" wydaje się nie mieć żadnego celu, z wyjątkiem ukrywania własnych błędów przed samym sobą. Jeśli naprawdę chcesz użyć funkcji try/except, zawsze powinieneś określać wyjątki, których się spodziewasz (w tym przypadku KeyError). W ten sposób nie będą przypadkowo ukrywać niepowiązanych błędów. Ale w tym przypadku, jeśli nie ma kodu w równoległym wątku modyfikującym "d", nigdy nie dostaniesz kluczowego błędu, ponieważ 'k' * musi * być w' d', ponieważ został zwrócony przez 'd.keys() '. –

Odpowiedz

8

Aby naprawić swoją funkcję, zmień del[k] na del d[k]. Nie ma funkcji do usuwania wartości ze słownika.

To, co robisz, polega na usuwaniu zmiennej k, w ogóle nie zmieniając słownika. Dlatego oryginalny słownik jest zawsze zwracany.

przepisany, czynność może wyglądać następująco:

def remove_empty_keys(d): 
    for k in d.keys(): 
     if not d[k]: 
      del d[k] 

Zakłada chcesz wyeliminować zarówno pustą listę i None wartości, a faktycznie usuwa pozycję z „false” wartości.

+0

W Pythonie 2, iteracja przez 'd.keys()' (która była listą) umożliwiła usunięcie wartości z pętli.W Pythonie 3 'd.keys()' jest [lazier] (https://docs.python.org/3/library/stdtypes.html#dict-views) Iteruj zamiast 'list (d)' lub skonstruuj nowy słownik jak w [@ mgilson's answer] (https://stackoverflow.com/a/14813423/1307866) – tiwo

6

Nie ma wbudowane do tego (AFAIK), ale można to zrobić łatwo ze zrozumieniem dict:

new_dict = {k:v for k,v in original_dict.items() if v} 

Jeśli utkniesz ze starszej wersji Pythona (pre 2.7 bez listowe DICT) możesz użyć konstruktora Dict:

new_dict = dict((k,v) for k,v in original_dict.items() if v) 

Pamiętaj, że to nie działa w miejscu (jak na twoje drugie pytanie). I słowniki nie obsługują zadanie kawałek jak list zrobić, więc najlepiej * naprawdę można zrobić, aby to wszystko zrobić na miejscu jest:

new_dict = {k:v for k,v in original_dict.items() if v} 
original_dict.clear() 
original_dict.update(new_dict) 

* oczywiście określenie „najlepsze” jest całkowicie subiektywna.

4

Można użyć dict ze zrozumieniem: -

>>> default = {'a': ['alpha'], 'b': ['beta','gamma'], 'g': []} 

>>> {key: value for key, value in default.iteritems() if value} 
{'a': ['alpha'], 'b': ['beta', 'gamma']} 
+0

Problem polega na tym, że nie modyfikuje on dyktatu, ponieważ go powtarzacie - wydaje mi się, że to może być OK (choć nie cytujcie mnie). To, że OP robi 'del [k]' zamiast 'del d [k]'. Wydaje mi się, że pierwszą formą jest utworzenie listy, a następnie usunięcie jej (chociaż mógłbym się mylić, ponieważ 'del' jest stwierdzeniem ... – mgilson

+0

@mgilson Tak, właśnie to zauważyłem. –

4
dict((k, v) for k, v in default.iteritems() if v) 

filtruje to wszystkie elementy, które nie są puste struny, pusty dict/krotka/list.

1

Michael's answer jest poprawna.

Cofając, może być w stanie uniknąć tworzenia tych pustych list w ogóle, przy użyciu collections.defaultdict(list)

>>> import collections 
>>> d = collections.defaultdict(list) 
>>> d 
defaultdict(<type 'list'>, {}) 
>>> d["hobbits"].append("Frodo") 
>>> d["hobbits"].append("Sam") 
>>> d 
defaultdict(<type 'list'>, {'hobbits': ['Frodo', 'Sam']}) 
1

jeszcze jedna opcja jest następujące (bez tworzenia nowego dict):

for e in [k for k,v in default.iteritems() if len(v) == 0]: default.pop(e) 
Powiązane problemy