回答:
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}
すべてのキーに値があることに注意してください。これらの値の一部が空の文字列であるだけです。値のないdictにはキーのようなものはありません。それが値を持っていなかった場合、それは口述にはありません。
.items()
。
{k: v for k, v in metadata.items() if v is not None}
BrenBarnのソリューションよりもさらに短くなる可能性があります(そして私はもっと読みやすいと思います)
{k: v for k, v in metadata.items() if v}
Python 2.7.3でテスト済み。
... if v!=None
:そうのように {k: v for k, v in metadata.items() if v!=None}
元の辞書を本当に変更する必要がある場合:
empty_keys = [k for k,v in metadata.iteritems() if not v]
for k in empty_keys:
del metadata[k]
空のキーのリストを作成する必要があることに注意してください。これは、辞書を反復処理している間は変更できないためです(お気付きかもしれませんが)。これは、空の値を持つエントリが多数ない限り、まったく新しい辞書を作成するよりも(メモリの点で)費用がかかりません。
.iteritems()
に.items()
、最初に最新のPythonのバージョンではもう動作しません。
BrenBarnのソリューションは理想的です(そしてPythonicic、私は追加するかもしれません)。ただし、これは別の(fp)ソリューションです。
from operator import itemgetter
dict(filter(itemgetter(1), metadata.items()))
ネストされていることが多く、サイクルを含むことさえある実世界のデータ構造を処理するためのフル機能を備えた簡潔なアプローチが必要な場合は、ボルトンユーティリティパッケージのリマップユーティリティを確認することをお勧めします。
iterutils.pyをプロジェクトにpip install boltons
コピーした後、次のようにします。
from boltons.iterutils import remap
drop_falsey = lambda path, key, value: bool(value)
clean = remap(metadata, visit=drop_falsey)
このページは、GithubのAPIからのはるかに大きなオブジェクトを操作するものを含む、さらに多くの例があります。
純粋なPythonなので、どこでも機能し、Python 2.7および3.3以降で完全にテストされています。何よりも、私はこのようなケースのためにそれを書いたので、それが処理できないケースを見つけたら、私にバグを修正してここで修正することができます。
ライアンの解決策に基づいて、リストとネストされた辞書もある場合:
Python 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
Python 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": "" }] }
ネストされた辞書があり、これが空のサブ要素でも機能するようにしたい場合は、BrenBarnの提案の再帰的な変形を使用できます。
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()
代わりに使用iteritems()
### 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の場合
dict((k, v) for k, v in metadata.items() if v)
以下からの回答に基づいて構築patriciaszとnneonneoあなたが唯一の特定のfalsyのもの(例えば持つキーを削除する場合がありますことを、そして可能性を占める''
)が、していない他の(例えば0
)、または多分あなたも、いくつかのtruthyものを含めたい(例えば'SPAM'
) 、それからあなたは非常に具体的なヒットリストを作ることができます:
unwanted = ['', u'', None, False, [], 'SPAM']
残念ながら、これは完全に機能しません。たとえば、0 in unwanted
はと評価されるためTrue
です。0
と他の偽物とを区別する必要があるため、次のものを使用する必要がありますis
。
any([0 is i for i in unwanted])
...に評価する False
ます。
次にdel
、不要なものに使用します。
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]
そのmetadata
場で変更する代わりに、新しい辞書が必要な場合:
newdict = {k: v for k, v in metadata.items() if not any([v is i for i in unwanted])}
[]
私はこのスレッドですべての返信を読み、一部はこのスレッドにも言及しました: 再帰関数でネストされた辞書の空の辞書を削除します
私はもともとここでソリューションを使用しましたが、うまくいきました:
試み1:熱すぎる(パフォーマンスも将来も保証されない):
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
しかし、Python 2.7の世界では、パフォーマンスと互換性の問題がいくつか提起されました。
isinstance
代わりに使用type
for
ループに展開して効率を上げるitems
代わりにpython3 safe を使用してくださいiteritems
試み2:冷たすぎ(メモ化が不十分):
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!これは再帰的ではなく、まったく覚え書きでもありません。
試行3:ちょうどいい(これまでのところ):
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):
使用してリストを処理し、元のscrub_dict(d)
実装を使用してリストをスクラブします。 @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
これを行う別の方法は、辞書内包表記を使用することです。これはと互換性があります2.7+
result = {
key: value for key, value in
{"foo": "bar", "lorem": None}.items()
if value
}
使用している場合のオプションは次のとおりです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_)
上記の一部のメソッドは、整数と浮動小数点値が存在する場合に無視します。値は0と0.0です。
上記を回避したい場合は、以下のコードを使用できます(ネストされた辞書とネストされたリストから空の文字列とNone値を削除します):
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
「私は現在、Pythonでの作業用にデスクトップアプリケーションも作成しているため、データ入力アプリケーションで大量のエントリがあり、必須ではないためにユーザーが空白のままにできることを確認しました。検証の目的で、簡単に取得できます。すべてのエントリを削除してから、辞書の空のキーまたは値を破棄します。したがって、上記の私のコードは、辞書の理解を使用して、空白ではない辞書の値要素を保持して、それらを簡単に取り出す方法を示しています。Python3.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
したがって、ループと削除は160nsで最速であり、リストの理解は約375nsで半分の速度になり、呼び出しを行うdict()
と再び680nsで半分の速度になります。
3を関数にラップすると、再び275nsに戻ります。また、私にとってPyPyはニートPythonの約2倍の速さでした。
list(dic.items())
ああ男ええええええええええええええええええええええええええええええええええええええええええええええええ、Python 3では真ですが、Python 2.7ではアイテムがリストを返すので、py 3 を呼び出さなければなりません。delは、Null /空の値の比率が低い場合でもより高速に見えます。そのリストを作成することは、dictを再作成することと同じくらいメモリ消費に悪いと思います。