Odpowiedzi:
Python 2.X
dict((k, v) for k, v in metadata.iteritems() if v)
Python 2.7 - 3.X
{k: v for k, v in metadata.items() if v is not None}
Pamiętaj, że wszystkie klucze mają wartości. Po prostu niektóre z tych wartości to pusty ciąg. W dyktandzie nie ma czegoś takiego jak klucz bez wartości; gdyby nie miał wartości, nie byłby w dyktandzie.
.items()
.
{k: v for k, v in metadata.items() if v is not None}
Może być jeszcze krótszy niż rozwiązanie BrenBarn (i myślę, że jest bardziej czytelny)
{k: v for k, v in metadata.items() if v}
Przetestowano w Pythonie 2.7.3.
... if v!=None
sposób: {k: v for k, v in metadata.items() if v!=None}
Jeśli naprawdę potrzebujesz zmodyfikować oryginalny słownik:
empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
del metadata[k]
Zauważ, że musimy zrobić listę pustych kluczy, ponieważ nie możemy modyfikować słownika podczas iteracji po nim (jak być może zauważyłeś). Jest to jednak mniej kosztowne (pod względem pamięci) niż tworzenie zupełnie nowego słownika, chyba że istnieje wiele wpisów z pustymi wartościami.
.iteritems()
go .items()
, pierwszy nie działa już w najnowszych wersjach Pythona.
Rozwiązanie BrenBarna jest idealne (i dodam, że jest pytoniczne ). Oto jednak inne (fp) rozwiązanie:
from operator import itemgetter
dict(filter(itemgetter(1), metadata.items()))
Jeśli chcesz mieć w pełni funkcjonalne, ale zwięzłe podejście do obsługi rzeczywistych struktur danych, które są często zagnieżdżone, a nawet mogą zawierać cykle, polecam przyjrzenie się narzędziu do remapowania z pakietu narzędzi boltons .
Po pip install boltons
skopiowaniu lub skopiowaniu iterutils.py do projektu po prostu wykonaj:
from boltons.iterutils import remap
drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)
Ta strona zawiera wiele innych przykładów, w tym te działające ze znacznie większymi obiektami z API Github.
Jest to czysty Python, więc działa wszędzie i jest w pełni przetestowany w Pythonie 2.7 i 3.3+. A co najlepsze, napisałem go dla dokładnie takich przypadków, więc jeśli znajdziesz przypadek, którego nie obsługuje, możesz mnie naprawić tutaj .
W oparciu o rozwiązanie Ryana , jeśli masz również listy i zagnieżdżone słowniki:
W przypadku Pythona 2:
def remove_empty_from_dict(d):
if type(d) is dict:
return dict((k, remove_empty_from_dict(v)) for k, v in d.iteritems() if v and remove_empty_from_dict(v))
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
else:
return d
W przypadku Pythona 3:
def remove_empty_from_dict(d):
if type(d) is dict:
return dict((k, remove_empty_from_dict(v)) for k, v in d.items() if v and remove_empty_from_dict(v))
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if v and remove_empty_from_dict(v)]
else:
return d
d = { "things": [{ "name": "" }] }
Jeśli masz zagnieżdżony słownik i chcesz, aby działał nawet dla pustych elementów podrzędnych, możesz użyć rekurencyjnego wariantu sugestii BrenBarna:
def scrub_dict(d):
if type(d) is dict:
return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
else:
return d
items()
zamiast iteritems()
dla Python 3
### example01 -------------------
mydict = { "alpha":0,
"bravo":"0",
"charlie":"three",
"delta":[],
"echo":False,
"foxy":"False",
"golf":"",
"hotel":" ",
}
newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(vdata) ])
print newdict
### result01 -------------------
result01 ='''
{'foxy': 'False', 'charlie': 'three', 'bravo': '0'}
'''
### example02 -------------------
mydict = { "alpha":0,
"bravo":"0",
"charlie":"three",
"delta":[],
"echo":False,
"foxy":"False",
"golf":"",
"hotel":" ",
}
newdict = dict([(vkey, vdata) for vkey, vdata in mydict.iteritems() if(str(vdata).strip()) ])
print newdict
### result02 -------------------
result02 ='''
{'alpha': 0,
'bravo': '0',
'charlie': 'three',
'delta': [],
'echo': False,
'foxy': 'False'
}
'''
W przypadku Pythona 3
dict((k, v) for k, v in metadata.items() if v)
Opierając się na odpowiedziach patriciasz i nneonneo i biorąc pod uwagę możliwość, że możesz chcieć usunąć klucze, które mają tylko pewne fałszywe rzeczy (np. ''
), Ale nie inne (np. 0
), A może nawet chcesz uwzględnić pewne prawdziwe rzeczy (np. 'SPAM'
) , wtedy możesz stworzyć bardzo szczegółową listę trafień:
unwanted = ['', u'', None, False, [], 'SPAM']
Niestety to nie do końca działa, ponieważ na przykład 0 in unwanted
wartościowane są do True
. Musimy rozróżniać 0
i inne fałszywe rzeczy, więc musimy użyć is
:
any([0 is i for i in unwanted])
... ocenia się do False
.
Teraz użyj go do del
niechcianych rzeczy:
unwanted_keys = [k for k, v in metadata.items() if any([v is i for i in unwanted])]
for k in unwanted_keys: del metadata[k]
Jeśli chcesz mieć nowy słownik, zamiast modyfikować metadata
w miejscu:
newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}
[]
Przeczytałem wszystkie odpowiedzi w tym wątku, a niektóre odniosły się również do tego wątku: Usuń puste dykty w zagnieżdżonym słowniku z funkcją rekurencyjną
Pierwotnie zastosowałem tutaj rozwiązanie i działało świetnie:
Próba 1: Too Hot (niewydajne lub przyszłościowe) :
def scrub_dict(d):
if type(d) is dict:
return dict((k, scrub_dict(v)) for k, v in d.iteritems() if v and scrub_dict(v))
else:
return d
Jednak w świecie Pythona 2.7 pojawiły się pewne problemy z wydajnością i zgodnością:
isinstance
zamiasttype
for
pętlę w celu zwiększenia wydajnościitems
zamiastiteritems
Próba 2: Za zimno (brak zapamiętania) :
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v,dict):
v = scrub_dict(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
DOH! To nie jest rekurencyjne i wcale nie jest zapamiętywane.
Próba 3: w sam raz (jak dotąd) :
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v,dict):
v = scrub_dict(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
if isinstance(v, list):
, który czyści listę przy użyciu oryginalnej scrub_dict(d)
implementacji. @staticmethod
def scrub_dict(d):
new_dict = {}
for k, v in d.items():
if isinstance(v, dict):
v = scrub_dict(v)
if isinstance(v, list):
v = scrub_list(v)
if not v in (u'', None, {}):
new_dict[k] = v
return new_dict
@staticmethod
def scrub_list(d):
scrubbed_list = []
for i in d:
if isinstance(i, dict):
i = scrub_dict(i)
scrubbed_list.append(i)
return scrubbed_list
Alternatywnym sposobem, w jaki możesz to zrobić, jest użycie rozumienia ze słownika. Powinno to być zgodne z2.7+
result = {
key: value for key, value in
{"foo": "bar", "lorem": None}.items()
if value
}
Oto opcja, jeśli używasz pandas
:
import pandas as pd
d = dict.fromkeys(['a', 'b', 'c', 'd'])
d['b'] = 'not null'
d['c'] = '' # empty string
print(d)
# convert `dict` to `Series` and replace any blank strings with `None`;
# use the `.dropna()` method and
# then convert back to a `dict`
d_ = pd.Series(d).replace('', None).dropna().to_dict()
print(d_)
Niektóre z wyżej wymienionych metod ignorują obecność liczb całkowitych i zmiennoprzecinkowe z wartościami 0 i 0,0
Jeśli ktoś chce uniknąć powyższego, może użyć poniższego kodu (usuwa puste ciągi i wartości None z zagnieżdżonego słownika i listy zagnieżdżonej):
def remove_empty_from_dict(d):
if type(d) is dict:
_temp = {}
for k,v in d.items():
if v == None or v == "":
pass
elif type(v) is int or type(v) is float:
_temp[k] = remove_empty_from_dict(v)
elif (v or remove_empty_from_dict(v)):
_temp[k] = remove_empty_from_dict(v)
return _temp
elif type(d) is list:
return [remove_empty_from_dict(v) for v in d if( (str(v).strip() or str(remove_empty_from_dict(v)).strip()) and (v != None or remove_empty_from_dict(v) != None))]
else:
return d
„Ponieważ obecnie piszę aplikację komputerową do pracy w języku Python, znalazłem w aplikacji do wprowadzania danych, w której jest dużo wpisów, a niektóre z nich nie są obowiązkowe, więc użytkownik może pozostawić ją pustą, w celu walidacji łatwo ją złapać wszystkie wpisy, a następnie odrzuć pusty klucz lub wartość słownika. Mój kod powyżej pokazuje, jak możemy je łatwo usunąć, używając rozumienia słownikowego i zachować element słownika, który nie jest pusty. Używam Pythona 3.8.3
data = {'':'', '20':'', '50':'', '100':'1.1', '200':'1.2'}
dic = {key:value for key,value in data.items() if value != ''}
print(dic)
{'100': '1.1', '200': '1.2'}
In [7]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: dic = {k: v for k, v in dic.items() if v is not None}
1000000 loops, best of 7: 375 ns per loop
In [8]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: dic = dict((k, v) for k, v in dic.items() if v is not None)
1000000 loops, best of 7: 681 ns per loop
In [10]: %%timeit dic = {str(i):i for i in xrange(10)}; dic['10'] = None; dic['5'] = None
...: for k, v in dic.items():
...: if v is None:
...: del dic[k]
...:
10000000 loops, best of 7: 160 ns per loop
więc pętla i usuwanie są najszybsze przy 160 ns, rozumienie listy jest o połowę wolniejsze przy ~ 375 ns iz wywołaniem dict()
jest znowu o połowę wolniejsze ~ 680 ns.
Pakowanie 3 do funkcji sprowadza ją z powrotem do około 275ns. Również dla mnie PyPy był około dwa razy szybszy niż Neet Python.
list(dic.items())
do py 3. Więc powiedz ze zrozumieniem? del nadal wydaje się szybszy przy niskim stosunku wartości Null / puste. Wydaje mi się, że tworzenie tej listy jest równie szkodliwe dla zużycia pamięci niż tylko odtworzenie dyktatu.