Bir emrim var ve boş değer dizeleri olan tüm anahtarları kaldırmak istiyorum.
metadata = {u'Composite:PreviewImage': u'(Binary data 101973 bytes)',
u'EXIF:CFAPattern2': u''}
Bunu yapmanın en iyi yolu nedir?
Bir emrim var ve boş değer dizeleri olan tüm anahtarları kaldırmak istiyorum.
metadata = {u'Composite:PreviewImage': u'(Binary data 101973 bytes)',
u'EXIF:CFAPattern2': u''}
Bunu yapmanın en iyi yolu nedir?
Yanıtlar:
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}
Tüm anahtarlarınızın değerleri olduğunu unutmayın. Sadece bu değerlerden bazıları boş dizedir. Değeri olmayan bir diktede anahtar diye bir şey yoktur; bir değeri olmasaydı, diktede olmazdı.
.items()
.
{k: v for k, v in metadata.items() if v is not None}
BrenBarn'ın çözümünden bile daha kısa olabilir (ve bence daha okunaklı)
{k: v for k, v in metadata.items() if v}
Python 2.7.3 ile test edilmiştir.
... if v!=None
: {k: v for k, v in metadata.items() if v!=None}
Orijinal sözlüğü gerçekten değiştirmeniz gerekiyorsa:
empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
del metadata[k]
Boş anahtarların bir listesini yapmamız gerektiğini unutmayın, çünkü bir sözlüğü yinelerken değiştiremeyiz (fark etmiş olabileceğiniz gibi). Bu, boş değerlere sahip çok sayıda giriş olmadığı sürece, yepyeni bir sözlük oluşturmaktan daha ucuzdur (bellek açısından).
.iteritems()
ile .items()
, öncelikle en son Python sürümleri artık çalışmaz.
BrenBarn'ın çözümü idealdir (ve ekleyebilirim pythonic). Bununla birlikte, işte başka bir (fp) çözümü:
from operator import itemgetter
dict(filter(itemgetter(1), metadata.items()))
Genellikle iç içe geçmiş ve hatta döngüleri içerebilen gerçek dünya veri yapılarını işlemek için tam özellikli, ancak özlü bir yaklaşım istiyorsanız , boltons yardımcı program paketinden remap yardımcı programına bakmanızı öneririm .
İterutils.py'yi projenize pip install boltons
kopyaladıktan veya kopyaladıktan sonra şunları yapın:
from boltons.iterutils import remap
drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)
Bu sayfada , Github API'sinden çok daha büyük nesnelerle çalışanlar dahil olmak üzere daha birçok örnek var.
Saf Python, bu yüzden her yerde çalışıyor ve Python 2.7 ve 3.3+ ile tamamen test edildi. Hepsinden iyisi, bunu tam olarak bunun gibi durumlar için yazdım, bu yüzden ele alınmadığı bir vaka bulursanız, hemen burada düzeltmem için beni rahatsız edebilirsiniz .
Ryan'ın çözümüne dayanarak, listeleriniz ve iç içe geçmiş sözlükleriniz varsa:
Python 2 için:
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
Python 3 için:
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": "" }] }
İç içe geçmiş bir sözlüğünüz varsa ve bunun boş alt öğeler için bile çalışmasını istiyorsanız, BrenBarn'ın önerisinin özyinelemeli bir varyantını kullanabilirsiniz:
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()
yerine kullanıniteritems()
### 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'
}
'''
Python 3 için
dict((k, v) for k, v in metadata.items() if v)
Patriciasz ve nneonneo'dan gelen yanıtlara dayanarak ve yalnızca belirli sahte şeyleri içeren (örneğin ''
) ancak diğerlerine sahip olmayan (örneğin ) anahtarları silmek isteyebileceğiniz olasılığını hesaba katarak 0
veya belki bazı doğru şeyleri dahil etmek isteyebilirsiniz (örneğin 'SPAM'
) , o zaman oldukça spesifik bir isabet listesi oluşturabilirsiniz:
unwanted = ['', u'', None, False, [], 'SPAM']
Ne yazık ki, bu pek işe yaramıyor, çünkü örneğin 0 in unwanted
değerlendiriyor True
. 0
Diğer sahte şeyleri ayırt etmemiz gerekiyor , bu yüzden kullanmalıyız is
:
any([0 is i for i in unwanted])
... olarak değerlendirilir False
.
Şimdi onu del
istenmeyen şeylerde kullanın:
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]
Yerinde değişiklik metadata
yapmak yerine yeni bir sözlük istiyorsanız :
newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}
[]
Bu konudaki tüm yanıtları okudum ve bazıları da bu konuya atıfta bulundu: İç içe geçmiş sözlükteki boş sözcükleri özyinelemeli işlevle kaldırın
Başlangıçta çözümü burada kullandım ve harika çalıştı:
Deneme 1: Çok Sıcak (performanslı veya geleceğe dönük değil) :
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
Ancak Python 2.7 dünyasında bazı performans ve uyumluluk endişeleri ortaya çıktı:
isinstance
yerine kullantype
for
verimlilik için liste kompozisyonunu döngü haline getirinitems
yerine python3 safe kullanıniteritems
Deneme 2: Çok Soğuk (Hatırlama Yoktur) :
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! Bu yinelemeli değildir ve hiç de hatırlatıcı değildir.
Deneme 3: Tam Doğru (şimdiye kadar) :
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):
orijinal scrub_dict(d)
uygulamayı kullanarak temizleyen ifade bloğuna sahip tutamaçlar listesidir . @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
Bunu yapmanın alternatif bir yolu, sözlük anlamayı kullanmaktır. Bu uyumlu olmalıdır2.7+
result = {
key: value for key, value in
{"foo": "bar", "lorem": None}.items()
if value
}
İşte kullanıyorsanız bir seçenek 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_)
Yukarıda bahsedilen Yöntemlerden bazıları, herhangi bir tam sayı varsa ve 0 ve 0.0 değerlerine sahip kayan nokta varsa yok sayar.
Birisi yukarıdakilerden kaçınmak isterse aşağıdaki kodu kullanabilir (iç içe geçmiş sözlük ve iç içe geçmiş listeden boş dizeleri ve Yok değerleri kaldırır):
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
"Şu anda Python ile çalışmam için bir masaüstü uygulaması da yazdığım için, veri girişi uygulamasında çok sayıda giriş olduğunda ve bazıları zorunlu olmadığında kullanıcı bunu boş bırakabilir, doğrulama amacıyla kapmak kolay tüm girişler ve sonra bir sözlüğün boş anahtarını veya değerini atın. Bu yüzden, bir sözlüğün üzerindeki kodum, sözlük anlamasını kullanarak bunları nasıl kolayca çıkarabileceğimizi ve boş olmayan sözlük değer öğesini saklayabileceğimizi gösterir. Python 3.8.3 kullanıyorum.
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
bu yüzden döngü ve silme 160ns'de en hızlı olanıdır, liste anlama ~ 375ns'de yarısı kadar yavaştır ve bir çağrı ile dict()
yine ~ 680ns'nin yarısı kadar yavaştır.
3'ü bir işleve sarmak, onu tekrar yaklaşık 275ns'ye düşürür. Ayrıca benim için PyPy, neet python'dan yaklaşık iki kat daha hızlıydı.
list(dic.items())
py 3'te çağırmanız gerekiyor . Öyleyse dict anlayış ftw? del, Null / boş değerlerin düşük bir oranı için hala daha hızlı görünüyor. Sanırım bu listeyi oluşturmak hafıza tüketimi için dikteyi yeniden oluşturmaktan daha kötü.