7

I have a nested dictionary and I want to be able to delete an arbitrary key inside of it.

The dictionary could look like this:

D={'key1':{'key2':{'key3':'value3', 'key4':'value4'}, 'key5':'value5'}}

But it could be of arbitrary size. The problem is that the keys should be taken from a "key list" looking, for example, like this:

key_list = ['key1', 'key2', 'key4']

key_list could be of arbitrary size and have any of the dictionary's keys in it.

Because of the above criteria, I can't just use:

del D['key1']['key2']['key4']

because I can't know beforehand which keys that key_list will contain.

So, how would a generic code look like that based on the content of key_list, deletes the corresponding item in the dictionary D?

PandaDeTapas
  • 516
  • 1
  • 7
  • 16
  • are you sure about the order of your `key_list` and if you want to delete the corresponding item it doesn't raise `KeyError` ! – Mazdak Nov 27 '14 at 21:12
  • No KeyError for me no. – PandaDeTapas Nov 27 '14 at 21:16
  • Two questions which might crystalize the problem in my mind: 1) Is the intent each time to remove a single key/value pair from the dictionary? 2) Is the sequence in which keys appear in key_list significant? I suppose the second question is much like what @Kasra is asking. – rchang Nov 27 '14 at 21:16
  • In your example, do you intend to treat the keys as a path to a deeply nested element in the dict and hence only delete the leaf? Or do you intend to delete every element whose key is given in your key_list? – Meitham Nov 27 '14 at 21:19
  • One additional question - can distinct keys appear multiple times in the dictionary (in different "levels", so to speak)? For example, D = {'key1':{'key1':'value1', 'key2':'value2'}} – rchang Nov 27 '14 at 21:20
  • Oh sorry fro not being clear enough. I mean to delete a single key/value pair, that is the most inner key or the "leaf" as @Meitham put it. The order in key_list is important, it is the order of the keys in the dictionary.Distinct keys can appear multiple times but if that's not possible I'll apreciate any other attempt to a solution. – PandaDeTapas Nov 27 '14 at 21:25

3 Answers3

7

You can use a for-loop to go through the values in key_list and navigate to the sub-dictionary that you want to remove the item from:

sub = D                 # Start with the full dictionary
for i in key_list[:-1]:
    sub = sub[i]        # Move down a level

In the end, sub will be the dictionary that you want to alter. All you need to do now is:

del sub[key_list[-1]]

since key_list[-1] is the key to remove.

Below is a demonstration:

>>> D={'key1':{'key2':{'key3':'value3', 'key4':'value4'}, 'key5':'value5'}}
>>> key_list = ['key1', 'key2', 'key4']
>>> sub = D
>>> for i in key_list[:-1]:
...     sub = sub[i]
...
>>> del sub[key_list[-1]]
>>> D
{'key1': {'key5': 'value5', 'key2': {'key3': 'value3'}}}
>>>

As you can see, this is equivalent to:

>>> D={'key1':{'key2':{'key3':'value3', 'key4':'value4'}, 'key5':'value5'}}
>>> del D['key1']['key2']['key4']
>>> D
{'key1': {'key5': 'value5', 'key2': {'key3': 'value3'}}}
>>>

except that the solution is dynamic (no hard-coded keys).

0

You can think of nested dictionaries, as a dictionary with multipart keys. If you transform your dict, then you decide when to delete an element. If part of the key is in the keylist, or any other criteria. Consider this:

D={'key1':{'key2':{'key3':'value3', 'key4':'value4', 'key7':{'key8':'value8'}}, 'key5':'value5'}, 'key6': 'value6'}

def multipart_key(d):
    dd = {}
    for k in d:
        if isinstance(d[k], dict):
            inner = multipart_key(d[k])
            for kk in inner:
                dd[k+chr(124)+kk] = inner[kk]
        else:
            dd[k] = d[k]
    return dd

key_list = ['key3', 'key7']

DD = multipart_key(D)
newDD = DD.copy()

for k in DD:
    for kk in k.split(chr(124)):
        if kk in key_list:
            del newDD[k]
            break

print(DD)
# {'key1|key2|key3': 'value3', 'key1|key5': 'value5', 'key6': 'value6', 'key1|key2|key7|key8': 'value8', 'key1|key2|key4': 'value4'}

print(newDD)
# {'key1|key5': 'value5', 'key6': 'value6', 'key1|key2|key4': 'value4'}
chapelo
  • 2,519
  • 13
  • 19
0

If you use NestedDict you can pop or delete any key as you would do in a flattened dictionary.

First let's initialize one:

from ndicts.ndicts import NestedDict

d = {'key1': {'key2': {'key3': 'value3', 'key4': 'value4'}, 'key5': 'value5'}}
nd = NestedDict(d)
key = ('key1', 'key2', 'key4')

Option 1

>>> del nd[key]

Option 2

>>> nd.pop(key)
'value4'

Note that this will delete an item in the original dictionary. To avoid this you can copy it when instantiating the NestedDict

nd = NestedDict(d, copy=True)

To install ndicts pip install ndicts

edd313
  • 1,109
  • 7
  • 20