web-dev-qa-db-fra.com

Supprimer un élément d'un dictionnaire

Existe-t-il un moyen de supprimer un élément d'un dictionnaire en Python?

De plus, comment puis-je supprimer un élément d'un dictionnaire pour en renvoyer une copie (c'est-à-dire sans modifier l'original)?

1184
richzilla

del statement supprime un élément:

del d[key]

Toutefois, cela modifie le dictionnaire existant afin que le contenu du dictionnaire change pour quiconque ayant une référence à la même instance. Pour retourner un nouveau dictionnaire , copiez-le:

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

Le constructeur dict() crée une copie peu profonde . Pour faire une copie en profondeur, voir le copy module .


Notez que faire une copie pour chaque dict del/affectation/etc. signifie que vous passez d'un temps constant à un temps linéaire et que vous utilisez également un espace linéaire. Pour les petits dict, ce n'est pas un problème. Mais si vous prévoyez de faire beaucoup de copies de gros dict, vous voulez probablement une structure de données différente, comme un HAMT (comme décrit dans cette réponse ).

1521
Greg Hewgill

pop modifie le dictionnaire.

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

Si vous souhaitez conserver l'original, vous pouvez simplement le copier.

205
Crystal

Je pense que votre solution est la meilleure façon de le faire. Mais si vous voulez une autre solution, vous pouvez créer un nouveau dictionnaire en utilisant les clés de l'ancien dictionnaire sans inclure votre clé spécifiée, comme ceci:

>>> 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'}
68
utdemir

Le del statement est ce que vous recherchez. Si vous avez un dictionnaire nommé foo avec une clé appelée 'bar', vous pouvez supprimer 'bar' de foo comme ceci:

_del foo['bar']
_

Notez que cela modifie en permanence le dictionnaire utilisé. Si vous souhaitez conserver le dictionnaire d'origine, vous devez au préalable en créer une copie:

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

L’appel dict effectue une copie superficielle. Si vous voulez une copie en profondeur, utilisez copy.deepcopy .

Voici une méthode que vous pouvez copier et coller, pour votre commodité:

_def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy
_
52
arussell84

Il y a beaucoup de bonnes réponses, mais je tiens à souligner une chose.

Vous pouvez utiliser à la fois la méthode dict.pop() et une méthode plus générique del pour supprimer des éléments d'un dictionnaire. Ils modifient tous deux le dictionnaire d'origine, vous devez donc en faire une copie (voir détails ci-dessous).

Et les deux lèveront un KeyError si la clé que vous leur fournissez n'est pas présente dans le dictionnaire:

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

et

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

Vous devez prendre soin de ceci:

en capturant l'exception:

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)

et

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)

en effectuant une vérification:

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

et

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

mais avec pop(), il existe également un moyen beaucoup plus concis: indiquez la valeur de retour par défaut:

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

Sauf si vous utilisez pop() pour obtenir la valeur d'une clé supprimée, vous pouvez fournir n'importe quoi, pas nécessaire None. Cependant, il est possible que l'utilisation de del avec in vérifie légèrement plus rapidement en raison du fait que pop() est une fonction générant des complications supplémentaires. Habituellement, ce n'est pas le cas, donc pop() avec la valeur par défaut est suffisant.


En ce qui concerne la question principale, vous devrez faire une copie de votre dictionnaire, pour sauvegarder le dictionnaire original et en avoir un nouveau sans que la clé ne soit supprimée.

Certaines personnes ici suggèrent de faire une copie complète (profonde) avec copy.deepcopy() , ce qui pourrait être une overkill, une copie "normale" (peu profonde), en utilisant copy.copy() ou dict.copy() , pourrait suffire. Le dictionnaire conserve une référence à l'objet en tant que valeur pour une clé. Ainsi, lorsque vous supprimez une clé d'un dictionnaire, cette référence est supprimée, pas l'objet référencé. L'objet lui-même peut être supprimé plus tard automatiquement par le ramasse-miettes, s'il n'y a pas d'autres références dans la mémoire. Effectuer une copie en profondeur nécessite davantage de calculs par rapport à une copie superficielle, ce qui diminue les performances du code en effectuant la copie, en gaspillant de la mémoire et en fournissant plus de travail au GC, une copie superficielle suffit parfois parfois.

Toutefois, si vous avez des objets modifiables en tant que valeurs de dictionnaire et prévoyez de les modifier ultérieurement dans le dictionnaire renvoyé sans la clé, vous devez en créer une copie complète.

Avec une copie superficielle:

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}

Avec copie profonde:

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}
45
Nikita
d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d

Résultat: d = {1: 2, '2': 3}

19
satels

… Comment puis-je supprimer un élément d’un dictionnaire pour renvoyer une copie (c’est-à-dire ne pas modifier l’original)?

dict est la mauvaise structure de données à utiliser pour cela.

Bien sûr, copier le dict et sortir de la copie fonctionne, tout comme la création d'un nouveau dict avec une compréhension, mais toute cette copie prend du temps: vous avez remplacé une opération à temps constant par une opération à temps linéaire. Et toutes ces copies en même temps prennent de la place, espace linéaire par copie.

D'autres structures de données, telles que essais de mappage de tableaux de hachage , sont conçues pour ce type de cas d'utilisation: l'ajout ou la suppression d'un élément renvoie une copie en temps logarithmique, en partageant le plus de son stockage avec l'original .1

Bien sûr, il y a des inconvénients. Les performances sont logarithmiques plutôt que constantes (bien qu'avec une base importante, généralement de 32 à 128). Et, bien que vous puissiez rendre l'API non-mutante identique à dict, l'API "en mutation" est évidemment différente. Et surtout, Python ne contient pas de piles HAMT.2

La bibliothèque pyrsistent est une implémentation assez solide des dict-remplacements basés sur HAMT (et de divers autres types) pour Python. Il possède même un astucieux API Evolver pour le transfert du code de mutation existant au code persistant de manière aussi fluide que possible. Mais si vous voulez être explicite sur le retour des copies plutôt que sur la mutation, utilisez-le simplement comme ceci:

>>> 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})

Cette d3 = d1.remove('a') est exactement ce que la question demande.

Si vous avez des structures de données modifiables telles que dict et list incorporées dans pmap, vous aurez toujours des problèmes d'aliasing. Vous ne pouvez résoudre ce problème qu'en devenant immuable, incorporant pmaps et pvectors.


1. Les HAMT sont également devenus populaires dans des langages comme Scala, Clojure, Haskell, car ils fonctionnent très bien avec une programmation sans verrouillage et une mémoire transactionnelle logicielle, mais aucun de ceux-ci n’est très pertinent en Python.

2. En fait, il y a un HAMT dans stdlib, utilisé dans l'implémentation de contextvars . Le PEP retiré antérieurement explique pourquoi. Mais il s'agit d'un détail d'implémentation masqué de la bibliothèque, pas d'un type de collection publique.

13
abarnert

Appelez simplement del d ['key'].

Cependant, en production, il est toujours recommandé de vérifier si la "clé" existe dans d.

if 'key' in d:
    del d['key']
13
Khanh Hua

Non, il n'y a pas d'autre moyen que

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

Cependant, créer souvent des copies de dictionnaires légèrement modifiés n’est probablement pas une bonne idée, car il en résultera des demandes de mémoire relativement importantes. Il est généralement préférable d’enregistrer l’ancien dictionnaire (si nécessaire), puis de le modifier.

7
phihag
# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)
6
daino3

Voici une approche de conception de haut niveau:

def eraseElement(d,k):
    if isinstance(d, dict):
        if k in d:
            d.pop(k)
            print(d)
        else:
            print("Cannot find matching key")
    else:
        print("Not able to delete")


exp = {'A':34, 'B':55, 'C':87}
eraseElement(exp, 'C')

Je passe le dictionnaire et la clé que je veux dans ma fonction, valide si c'est un dictionnaire et si la clé est correcte, et si les deux existent, supprime la valeur du dictionnaire et imprime les restes.

Sortie: {'B': 55, 'A': 34}

J'espère que ça t'as aidé!

5
喬治扎菲
>>> def delete_key(dict, key):
...     del dict[key]
...     return dict
... 
>>> test_dict = {'one': 1, 'two' : 2}
>>> print delete_key(test_dict, 'two')
{'one': 1}
>>>

cela ne fait aucune gestion d'erreur, il suppose que la clé est dans le dict, vous voudrez peut-être vérifier cela d'abord et raise si ce n'est pas

5
tMC

L'extrait de code ci-dessous vous aidera certainement, j'ai ajouté des commentaires dans chaque ligne qui vous aideront à comprendre le code.

def execute():
   dic = {'a':1,'b':2}
   dic2 = remove_key_from_dict(dic, 'b')  
   print(dict2)           # {'a': 1}
   print(dict)            # {'a':1,'b':2}

def remove_key_from_dict(dictionary_to_use, key_to_delete):
   copy_of_dict = dict(dictionary_to_use)     # creating clone/copy of the dictionary
   if key_to_delete in copy_of_dict :         # checking given key is present in the dictionary
       del copy_of_dict [key_to_delete]       # deleting the key from the dictionary 
   return copy_of_dict                        # returning the final dictionary

ou vous pouvez aussi utiliser dict.pop ()

d = {"a": 1, "b": 2}

res = d.pop("c")  # No `KeyError` here
print (res)       # this line will not execute

ou la meilleure approche est

res = d.pop("c", "key not found")
print (res)   # key not found
print (d)     # {"a": 1, "b": 2}

res = d.pop("b", "key not found")
print (res)   # 2
print (d)     # {"a": 1}
3
Mayur Agarwal

Voici une autre variante utilisant la compréhension de liste:

original_d = {'a': None, 'b': 'Some'}
d = dict((k,v) for k, v in original_d.iteritems() if v)
# result should be {'b': 'Some'}

L’approche est basée sur une réponse de cet article: Méthode efficace pour supprimer les clés avec des chaînes vides d’un dict

2
BigBlueHat
    species = {'HI': {'1': (1215.671, 0.41600000000000004),
  '10': (919.351, 0.0012),
  '1025': (1025.722, 0.0791),
  '11': (918.129, 0.0009199999999999999),
  '12': (917.181, 0.000723),
  '1215': (1215.671, 0.41600000000000004),
  '13': (916.429, 0.0005769999999999999),
  '14': (915.824, 0.000468),
  '15': (915.329, 0.00038500000000000003),
 'CII': {'1036': (1036.3367, 0.11900000000000001), '1334': (1334.532, 0.129)}}

Le code suivant fera une copie de dict species et supprimera les éléments qui ne sont pas dans trans_HI

trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
    if transition not in trans_HI:
        species['HI'].pop(transition)
0
Schlator