辞書から要素を削除する

2011年05月01日に質問されました。  ·  閲覧回数 1.8M回  ·  ソース

richzilla picture
2011年05月01日

Pythonで辞書からアイテムを削除する方法はありますか?

さらに、辞書からアイテムを削除してコピーを返す(つまり、元のアイテムを変更しない)にはどうすればよいですか?

回答

Greg Hewgill picture
2011年05月01日
1885

delステートメントは要素

del d[key]

ただし、これにより既存の辞書が変更されるため、同じインスタンスへの参照を持つ他のユーザーの辞書の内容が変更されます。 新しい辞書を返すには、辞書のコピーを作成します。

def removekey(d, key):
    r = dict(d)
    del r[key]
    return r

dict()コンストラクターは浅いコピーを作成します。 ディープコピーを作成するには、 copyモジュールを参照してください。


すべてのdict del / Assignment / etcのコピーを作成することに注意してください。 つまり、一定時間から線形時間に移行し、線形空間も使用します。 小さな口述の場合、これは問題ではありません。 ただし、大きなdictのコピーを大量に作成する場合は、HAMTなどの別のデータ構造が必要になる可能性があります(この回答で説明され

Crystal picture
2014年03月22日
307

popは辞書を変更します。

 >>> lol = {"hello": "gdbye"}
 >>> lol.pop("hello")
     'gdbye'
 >>> lol
     {}

オリジナルを保持したい場合は、それをコピーすることができます。

utdemir picture
2011年05月01日
89

私はあなたの解決策がそれを行うための最良の方法だと思います。 ただし、別の解決策が必要な場合は、次のように、指定したキーを含めずに、古い辞書のキーを使用して新しい辞書を作成できます。

>>> a
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> {i:a[i] for i in a if i!=0}
{1: 'one', 2: 'two', 3: 'three'}
Nikita picture
2017年09月22日
59

いい答えはたくさんありますが、一つ強調したいのですが。

dict.pop()メソッドとより一般的なdelステートメントの両方を使用して、辞書から項目を削除できます。 どちらも元の辞書を変更するため、コピーを作成する必要があります(以下の詳細を参照)。

そして、あなたが彼らに提供している鍵が辞書に存在しない場合、彼らは両方ともKeyErrorを調達します:

key_to_remove = "c"
d = {"a": 1, "b": 2}
del d[key_to_remove]  # Raises `KeyError: 'c'`

そして

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove)  # Raises `KeyError: 'c'`

あなたはこれを世話する必要があります:

例外をキャプチャすることによって:

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    del d[key_to_remove]
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

そして

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    d.pop(key_to_remove)
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

チェックを実行することによって:

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    del d[key_to_remove]

そして

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    d.pop(key_to_remove)

しかし、 pop()すると、はるかに簡潔な方法もあります。デフォルトの戻り値を指定します。

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove, None)  # No `KeyError` here

削除されるキーの値を取得するためにpop()を使用しない限り、 Noneでなくても、何でも提供できます。 delinチェックとともに使用すると、 pop()が独自の複雑さを伴う関数であるため、オーバーヘッドが発生するため、わずかに高速になる可能性があります。 通常はそうではないので、デフォルト値のpop()で十分です。


主な質問については、辞書のコピーを作成して、元の辞書を保存し、キーを削除せずに新しい辞書を作成する必要があります。

ここにいる他の何人かの人々は、 copy.copy()またはdict.copy()copy.deepcopy()で完全な(深い)コピーを作成することを提案します。十分かもしれません。 ディクショナリは、オブジェクトへの参照をキーの値として保持します。 したがって、ディクショナリからキーを削除すると、参照されているオブジェクトではなく、この参照が削除されます。 オブジェクト自体は、メモリ内に他の参照がない場合、ガベージコレクタによって後で自動的に削除される可能性があります。 ディープコピーを作成するには、シャローコピーに比べてより多くの計算が必要になるため、コピーを作成し、メモリを浪費し、GCにより多くの作業を提供することで、コードのパフォーマンスが低下します。シャローコピーで十分な場合もあります。

ただし、ディクショナリ値として可変オブジェクトがあり、キーなしで返されたディクショナリで後でそれらを変更する予定の場合は、ディープコピーを作成する必要があります。

浅いコピーの場合:

def get_dict_wo_key(dictionary, key):
    """Returns a **shallow** copy of the dictionary without a key."""
    _dict = dictionary.copy()
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}

ディープコピー付き:

from copy import deepcopy


def get_dict_wo_key(dictionary, key):
    """Returns a **deep** copy of the dictionary without a key."""
    _dict = deepcopy(dictionary)
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}
arussell84 picture
2011年05月01日
57

デルステートメントはあなたが探しているものです。 'bar'というキーを持つfooという名前の辞書がある場合、次のようにfooから 'bar'を削除できます。

del foo['bar']

これにより、操作対象の辞書が永続的に変更されることに注意してください。 元の辞書を保持したい場合は、事前にコピーを作成する必要があります。

>>> foo = {'bar': 'baz'}
>>> fu = dict(foo)
>>> del foo['bar']
>>> print foo
{}
>>> print fu
{'bar': 'baz'}

dict呼び出しは、浅いコピーを作成します。 ディープコピーが必要な場合は、 copy.deepcopy

便利なように、コピーして貼り付ける方法は次のとおりです。

def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy
abarnert picture
2018年05月15日
28

…辞書からアイテムを削除してコピーを返すにはどうすればよいですか(つまり、元のアイテムを変更しないでください)。

dictは、これに使用するのに間違ったデータ構造です。

確かに、dictをコピーしてコピーからポップすることは機能し、理解を持って新しいdictを構築することもできますが、そのコピーにはすべて時間がかかります。定数時間の操作を線形時間の操作に置き換えました。 そして、一度に生きているすべてのコピーはスペースを取ります—コピーごとの線形スペース。

ハッシュ配列マップ試行などの他のデータ構造は、まさにこの種のユースケース向けに設計されています。要素を追加または削除すると、対数時間でコピーそのストレージのほとんどが元のと共有されます。 1

もちろん、いくつかの欠点があります。 パフォーマンスは一定ではなく対数です(ただし、ベースが大きく、通常は32〜128です)。 また、非変更APIをdictと同一にすることはできますが、「変更」APIは明らかに異なります。 そして、何よりも、Pythonに含まれているHAMTバッテリーはありません。 2

pyrsistentライブラリは、Python用のHAMTベースのdict-replacements(およびその他のさまざまなタイプ)のかなり堅実な実装です。 既存の変更コードを永続コードに可能な限りスムーズに移植するための気の利いたエボリューターAPIもあり

>>> from pyrsistent import m
>>> d1 = m(a=1, b=2)
>>> d2 = d1.set('c', 3)
>>> d3 = d1.remove('a')
>>> d1
pmap({'a': 1, 'b': 2})
>>> d2
pmap({'c': 3, 'a': 1, 'b': 2})
>>> d3
pmap({'b': 2})

そのd3 = d1.remove('a')は、まさに質問が求めているものです。

あなたのような可変データ構造持っていればdictlistに埋め込まpmap 、あなたはまだエイリアシングています問題-あなただけの不変行くことによってそれを修正することができ、すべてのpmappvector埋め込みます。


1. HAMTは、ロックフリープログラミングとソフトウェアトランザクショナルメモリで非常にうまく機能するため、Scala、Clojure、Haskellなどの言語でも人気がありますが、どちらもPythonではあまり関係がありません。

2.実際の実装で使用されるSTDLIBでHAMTがあり contextvars ただし、これはライブラリの非表示の実装の詳細であり、パブリックコレクションタイプではありません。

satels picture
2011年05月01日
19
d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d

結果: d = {1: 2, '2': 3}

Khanh Hua picture
2015年03月02日
14

del d ['key']を呼び出すだけです。

ただし、本番環境では、dに「キー」が存在するかどうかを確認することをお勧めします。

if 'key' in d:
    del d['key']
phihag picture
2011年05月01日
7

いいえ、他に方法はありません

def dictMinus(dct, val):
   copy = dct.copy()
   del copy[val]
   return copy

ただし、わずかに変更された辞書のコピーを作成することは、比較的大きなメモリ需要をもたらすため、おそらく良い考えではありません。 通常は、(必要な場合でも)古い辞書をログに記録してから変更することをお勧めします。

daino3 picture
2017年08月06日
7
# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)