Domanda

C'è un modo per eliminare un oggetto da un dizionario a Python?

Inoltre, come posso eliminare un elemento da un dizionario per restituire una copia (cioè non modificare l'originale)?

È stato utile?

Soluzione

Il del dichiarazione rimuove un elemento:

del d[key]

Tuttavia, ciò muta il dizionario esistente in modo che il contenuto del dizionario cambi per chiunque altro abbia un riferimento alla stessa istanza. Per restituire a nuovo Dizionario, crea una copia del dizionario:

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

Il dict() il costruttore fa un copia superficiale. Per fare una copia profonda, vedere il copy modulo.


Si noti che fare una copia per ogni detto del/Assegnazione/ecc. significa che stai passando dal tempo costante al tempo lineare e anche usando spazio lineare. Per i piccoli dettami, questo non è un problema. Ma se hai intenzione di fare molte copie di grandi dettami, probabilmente vuoi una struttura di dati diversa, come un HAMT (come descritto in questa risposta).

Altri suggerimenti

pop Muta il dizionario.

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

Se vuoi mantenere l'originale, potresti semplicemente copiarlo.

Penso che la tua soluzione sia il modo migliore per farlo. Ma se vuoi un'altra soluzione, puoi creare un nuovo dizionario con l'utilizzo delle chiavi del vecchio dizionario senza includere la chiave specificata, come questa:

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

Il DEL Dichiarazione è quello che stai cercando. Se hai un dizionario chiamato Foo con una chiave chiamata "bar", puoi eliminare "bar" da foo come questo:

del foo['bar']

Si noti che ciò modifica in modo permanente il dizionario su cui gestisce. Se vuoi mantenere il dizionario originale, dovrai creare una copia in anticipo:

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

Il dict La chiamata fa una copia superficiale. Se vuoi una copia profonda, usa copy.deepcopy.

Ecco un metodo che puoi copiare e incollare, per comodità:

def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy

Ci sono molte belle risposte, ma voglio sottolineare una cosa.

Puoi usare entrambi dict.pop() metodo e un più generico del dichiarazione Per rimuovere gli elementi da un dizionario. Entrambi mutano il dizionario originale, quindi è necessario fare una copia (vedere i dettagli di seguito).

Ed entrambi aumenteranno a KeyError Se la chiave che stai fornendo loro non è presente nel dizionario:

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

e

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

Devi prenderti cura di questo:

catturando l'eccezione:

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)

e

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)

eseguendo un assegno:

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

e

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

ma con pop() C'è anche un modo molto più conciso: fornire il valore di restituzione predefinito:

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

A meno che tu non usi pop() Per ottenere il valore di una chiave rimossa puoi fornire qualsiasi cosa, non è necessario None. Anche se potrebbe essere che usando del insieme a in Controllare è leggermente più veloce a causa di pop() Essere una funzione con le proprie complicazioni causando un sovraccarico. Di solito non è così, quindi pop() con il valore predefinito è abbastanza buono.


Per quanto riguarda la domanda principale, dovrai fare una copia del tuo dizionario, per salvare il dizionario originale e averne uno nuovo senza che la chiave venga rimossa.

Alcune altre persone qui suggeriscono di fare una copia (profonda) piena con copy.deepcopy(), che potrebbe essere un overkill, una copia "normale" (superficiale), usando copy.copy() o dict.copy(), potrebbe essere sufficiente. Il dizionario mantiene un riferimento all'oggetto come valore per una chiave. Quindi, quando si rimuove una chiave da un dizionario, questo riferimento viene rimosso, non l'oggetto referenziato. L'oggetto stesso può essere rimosso in seguito automaticamente dal Garbage Collector, se non ci sono altri riferimenti per esso nella memoria. Fare una copia profonda richiede più calcoli rispetto alla copia superficiale, quindi diminuisce le prestazioni del codice facendo la copia, sprecando la memoria e fornendo più lavoro al GC, a volte è sufficiente una copia superficiale.

Tuttavia, se si dispone di oggetti mutabili come valori del dizionario e prevedi di modificarli più avanti nel dizionario restituito senza la chiave, devi fare una copia profonda.

Con copia superficiale:

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}

Con una copia profonda:

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

Risultato: d = {1: 2, '2': 3}

... Come posso eliminare un elemento da un dizionario per restituire una copia (cioè non modificare l'originale)?

UN dict è la struttura dei dati sbagliata da utilizzare per questo.

Certo, copiare il detto e far scoppiare le opere di copia, così come costruire un nuovo detto con una comprensione, ma tutto ciò che la copia richiede tempo: hai sostituito un'operazione a tempo costante con uno a tempo lineare. E tutte quelle copie vive subito occupano spazio, spazio lineare per copia.

Altre strutture di dati, come tentativi mappati in array hash, sono progettati esattamente per questo tipo di caso d'uso: l'aggiunta o la rimozione di un elemento restituisce una copia In tempo logaritmico, condividendo la maggior parte del suo spazio di archiviazione con l'originale.1

Ovviamente ci sono alcuni aspetti negativi. Le prestazioni sono logaritmiche piuttosto che costanti (sebbene con una base ampia, di solito 32-128). E, mentre puoi rendere l'API non mutante identica a dict, l'API "mutante" è ovviamente diversa. E, soprattutto, non ci sono batterie HAMT incluse con Python.2

Il pyrsistent La biblioteca è un'implementazione piuttosto solida di restituni da DICT basati su HAMT (e vari altri tipi) per Python. Ha anche un elegante API Evolver Per portare il codice di mutazione esistente al codice persistente nel modo più fluido possibile. Ma se vuoi essere esplicito sul ritorno delle copie piuttosto che sulla mutamento, lo usi semplicemente in questo modo:

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

Quella d3 = d1.remove('a') è esattamente ciò che la domanda sta chiedendo.

Se hai strutture di dati mutabili come dict e list incorporato nel pmap, avrai ancora problemi di aliasing: puoi risolverlo solo andando immutabile fino in fondo, incorporando pmapsabbia pvectorS.


1. Gli Hamts sono diventati anche popolari in linguaggi come Scala, Clojure, Haskell perché giocano molto bene con la programmazione senza blocchi e la memoria transazionale del software, ma nessuno di questi è molto rilevante in Python.

2. In effetti, lì è un hamt nello stdlib, utilizzato nell'implementazione di contextvars. Il PEP precedentemente ritirato spiega il perché. Ma questo è un dettaglio di implementazione nascosto della biblioteca, non un tipo di raccolta pubblica.

Chiama semplicemente Del D ['Key'].

Tuttavia, in produzione, è sempre una buona pratica verificare se esiste "chiave" in d.

if 'key' in d:
    del d['key']

No, non c'è altro modo di

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

Tuttavia, spesso creare copie di dizionari solo leggermente alterati non è probabilmente una buona idea perché si tradurrà in richieste di memoria relativamente grande. Di solito è meglio registrare il vecchio dizionario (se necessario) e quindi modificarlo.

# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 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}
>>>

Questo non esegue alcuna gestione degli errori, presuppone che la chiave sia nel detto, potresti voler controllare prima e raise se non lo è

Qui un approccio di design di alto livello:

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

Sto passando il dizionario e la chiave che desidero nella mia funzione, convalida se è un dizionario e se la chiave va bene, e se esistono entrambi, rimuove il valore dal dizionario e stampa i rimasti.

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

Spero possa aiutare!

Di seguito Snippet del codice ti aiuterà sicuramente, ho aggiunto commenti in ogni riga che ti aiuterà a comprendere il codice.

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

oppure puoi anche usare dict.pop ()

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

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

o l'approccio migliore è

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}

Ecco un'altra variazione usando la comprensione dell'elenco:

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'approccio si basa su una risposta di questo post:Modo efficiente per rimuovere le chiavi con stringhe vuote da un detto

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

Il seguente codice farà una copia di Dict species ed eliminare gli articoli che non sono in trans_HI

trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
    if transition not in trans_HI:
        species['HI'].pop(transition)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top