2013-02-11 3 views
5

У меня есть словарь, как:Python: элегантный способ удалить пустые списки из словаря Python

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

Я хочу, чтобы исключить пустые значения, как:

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

Я написал функцию (после пример нашел в Интернете)

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

у меня есть следующие вопросы:

1- я не нашел ошибку, почему она всегда возвращает следующее -

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

2- Есть встроенная функция для устранения/удалить Null/NONE/пустые значения из словаря Python без создания копия исходного словаря?

+1

Ваш вопрос, кажется, смешивает идею «Нет» с пустыми списками. Это затрудняет понимание. –

+0

Возможно, лучший способ сказать, что это будет «Есть ли функция для устранения ложных значений из словаря» – mgilson

+0

Ваша статья «try ... except», похоже, не имеет никакой цели, кроме как скрыть свои собственные ошибки от вас самих. Если вы действительно хотите использовать try/except, тогда вы всегда должны указывать исключение (ы), которое вы ожидаете (в данном случае KeyError). Таким образом, они не будут непреднамеренно скрывать несвязанные ошибки. Но в этом случае, если в параллельном потоке не существует кода, который модифицирует 'd', вы никогда не получите ключевую ошибку, потому что' k' * must * находится в 'd', поскольку он был возвращен' d.keys() '. –

ответ

8

Чтобы исправить вашу функцию, измените del[k] на del d[k]. Нет функции для удаления значений из словаря.

Что вы делаете, это удаление переменной k, не меняя словарь вообще. Поэтому исходный словарь всегда возвращается.

переписана ваша функция может выглядеть следующим образом:

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

Это предполагает, что вы хотите, чтобы устранить как пустой список и None значения, а на самом деле удаляет элемент с «ложным» значением.

+0

В Python 2, итерация по 'd.keys()' (который был списком) позволил удалить значения в цикле. В Python 3 'd.keys()' is [lazier] (https://docs.python.org/3/library/stdtypes.html#dict-views). Вместо этого перейдите к 'list (d)' или создайте новый словарь, как в ответе [@ mgilson] (https://stackoverflow.com)./а/14813423/1307866) – tiwo

6

Там нет встроенного для этого (AFAIK), но вы можете сделать это легко с Dict пониманием:

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

Если вы застряли с более старой версией питона (до 2,7 без Dict постижений), вы можете использовать конструктор dict:

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

Обратите внимание, что это не работает на месте (согласно вашему второму вопросу). А словари не поддерживают назначение ломтика как списки делают, поэтому лучший * вы можете действительно сделать, чтобы получить все это сделано в месте:

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

* конечно термин «лучший» является полностью субъективным.

4

Вы можете использовать Dict понимание: -

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

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

Проблема не в том, чтобы изменить dict, когда вы повторяете его - я на самом деле думаю, что это может быть ОК (хотя не цитируйте меня на этом). Это то, что OP делает 'del [k]' вместо 'del d [k]'. Мне кажется, что первая форма создает список, а затем удаляет его (хотя я мог ошибаться в этом, так как 'del' - это заявление ... – mgilson

+0

@mgilson. Да, я заметил это. Я удалю эту строку. –

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

Это фильтрует все элементы, которые не являются пустыми строками, пустой ДИКТ/кортеж/список.

1

Michael's answer является правильным.

Отступив, вы можете быть в состоянии избежать создания этих пустых списков вообще, с использованием 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

еще один вариант заключается в следующем (без создания нового Dict):

for e in [k for k,v in default.iteritems() if len(v) == 0]: default.pop(e) 
Смежные вопросы