キーが不明なときにアイテムを辞書から削除する


112

値によってディクショナリからアイテムを削除する最良の方法は何ですか。つまり、アイテムのキーが不明な場合。ここに簡単なアプローチがあります:

for key, item in some_dict.items():
    if item is item_to_remove:
        del some_dict[key]

もっと良い方法はありますか?ディクショナリの反復中にディクショナリから変更(アイテムを削除)することに問題はありますか?


1
反復中のdictの変更を禁止する下線の理由は、内部的に反復の順序があるためです。キーを変更すると、順序が損なわれ、未知の動作が発生します。
スペクトル

回答:


92

現在、オブジェクトの同一性をテストしていることに注意してください(両方のオペランドがメモリ内の同じオブジェクトによって表されている場合にisのみ返さTrueれます。これは、と比較する2つのオブジェクトが常にそうであるとは限りません==)。これを意図的に行う場合は、コードを次のように書き直すことができます。

some_dict = {key: value for key, value in some_dict.items() 
             if value is not value_to_remove}

しかし、これはあなたが望むことをしないかもしれません:

>>> some_dict = {1: "Hello", 2: "Goodbye", 3: "You say yes", 4: "I say no"}
>>> value_to_remove = "You say yes"
>>> some_dict = {key: value for key, value in some_dict.items() if value is not value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 3: 'You say yes', 4: 'I say no'}
>>> some_dict = {key: value for key, value in some_dict.items() if value != value_to_remove}
>>> some_dict
{1: 'Hello', 2: 'Goodbye', 4: 'I say no'}

したがって、おそらくの!=代わりにしたいでしょうis not


2
それは辞書圧縮ですか?彼らはいつ追加されましたか?
Buttons840

4
あなたは使用することができsome_dict.iteritems()、ここでとプットforif読みやすさのために別の行に文
JFS

3
Python 2.7で辞書内包表記が追加されたと思います。
ミトランディ

2
@JF Sebastian:私はPython 3を使っており、iteritems今はitemsです。Python 2.7では、iteritems()本当に優れています。
Tim Pietzcker、2011年

1
@ Buttons840それらは、PEP 274またはディクショナリディスプレイdict内包と呼ばれます。PEPが言うように、それらは2.7でバックポートされた3.xの特技として追加されました。あるいはdict()、適切なジェネレータ式(2.4)でフィードすることもできます。メタ:何かを見つけるためにここペプ閲覧できます。
n611x007

120

このdict.pop(key[, default])メソッドでは、キーがわかっているときにアイテムを削除できます。アイテムを削除した場合は、キーの値を返しますdefault。それ以外の場合は、渡されたものを返します。ドキュメントを参照してください。 '

例:

>>> dic = {'a':1, 'b':2}
>>> dic
{'a': 1, 'b': 2}
>>> dic.pop('c', 0)
0
>>> dic.pop('a', 0)
1
>>> dic
{'b': 2}

4
OPはキーが不明な場合について尋ねました
nmz787


42

delpop()の簡単な比較:

import timeit
code = """
results = {'A': 1, 'B': 2, 'C': 3}
del results['A']
del results['B']
"""
print timeit.timeit(code, number=100000)
code = """
results = {'A': 1, 'B': 2, 'C': 3}
results.pop('A')
results.pop('B')
"""
print timeit.timeit(code, number=100000)

結果:

0.0329667857143
0.0451040902256

したがって、delpop()よりも高速です。


6
ただし、パフォーマンスの違いはそれほど大きくなく、例外の発生を回避したい場合は、pop()(@ n-1-1が上記のように)2番目の引数を指定できますdel。これは、演算子のオプションではありません。
Alex Dupuy 2014

1
質問の補足ですが、私も理解するのに苦労していましたtimeit。この明確な例をありがとう。
Adam_G、2015年

OPは、キーが不明な場合について尋ねました。この回答は、キーが既知であることを前提としています。
ジャン=フランソワ・コルベット

7

items()リストを返します、そしてそれはあなたが反復しているそのリストなので、ループ内のdictを変更することはここでは問題ではありません。iteritems()代わりに使用している場合、ループ内でdictを変更すると問題が発生しviewitems()Python 2.7 でも同様です。

値によって辞書からアイテムを削除するより良い方法を考えることができません。


7

削除が必要なキーのリストを作成してから削除します。シンプルで効率的であり、dictの反復と変更を同時に行うことによる問題を回避します。

keys_to_remove = [key for key, value in some_dict.iteritems()
                  if value == value_to_remove]
for key in keys_to_remove:
    del some_dict[key]

OPは、キーが不明な場合について尋ねました。この回答は、キーが既知であることを前提としています。
ジャン=フランソワ・コルベット


1
y={'username':'admin','machine':['a','b','c']}
if 'c' in y['machine'] : del y['machine'][y['machine'].index('c')]

0

あなたが提案したように、反復中にディクショナリからアイテムを削除することに問題はありません。同時に同じディクショナリを使用する複数のスレッドに注意してください。これにより、KeyErrorまたはその他の問題が発生する可能性があります。

もちろん、http: //docs.python.org/library/stdtypes.html#typesmappingにあるドキュメントを参照してください


for k,v in d.iteritems(): del d[k]与えるだろうRuntimeError: dictionary changed size during iteration。ミトランディの説明を参照してください。
Buttons840 '27年

1
もちろん、d.iteritems()は元のポスターがどのように反復されているかではなく、私の回答で言及していたものではありません。
Thane Anthem

0

これが私のやり方です。

for key in some_dict.keys():
    if some_dict[key] == item_to_remove:
        some_dict.pop(key)
        break
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.