Ravi
Ravi

Reputation: 143

Deleting Items based on Keys in nested Dictionaries in python

I have a dictonary that looks something like this:

{
    'key1': 
        {
            'a': 'key1', 
            'b': 'val1', 
            'c': 'val2'
        }, 
    'key2': 
        {
            'a': 'key2', 
            'b': 'val3', 
            'c': 'val4'
        }, 
    'key3': 
        {
            'a': 'key3', 
            'b': 'val5', 
            'c': 'val6'
        }
}

I trying to delete the elements in the nested dict based on the key "a" to get an output like this:

{
    'key1': 
        {
            'b': 'val1', 
            'c': 'val2'
        }, 
    'key2': 
        {
            'b': 'val3', 
            'c': 'val4'
        }, 
    'key3': 
        {
            'b': 'val5', 
            'c': 'val6'
        }
}

I wrote the following snippet for it:

for k in dict_to_be_deleted:
    del k["a"]

I keep getting Key Error: k not found. I tried the following method as well:

for i in dict_to_be_deleted:
    for k,v in i.items():
        if "a" in k:
            del i[k]

I get

Attribute Error: str object has no attribute items

But isn't it suppose to be a dictionary since dict_to_be_deleted is a nested dictionary? I am pretty confused with this. I greatly appreciate any pointers in this regard.

Upvotes: 6

Views: 9431

Answers (5)

user9158931
user9158931

Reputation:

Why you are deleting when you can extract what you need ? Here is collections.defaultdict(dict) approach:

data={
    'key1':
        {
            'a': 'key1',
            'b': 'val1',
            'c': 'val2'
        },
    'key2':
        {
            'a': 'key2',
            'b': 'val3',
            'c': 'val4'
        },
    'key3':
        {
            'a': 'key3',
            'b': 'val5',
            'c': 'val6'
        }
}

import collections

dict_1=collections.defaultdict(dict)
for key,value in data.items():
    for key_1,value_1 in value.items():
        if key!='a':
            dict_1[key][key_1]=value_1

print(dict_1)

output:

{
  "key1": {
    "b": "val1",
    "c": "val2"
  },
  "key2": {
    "b": "val3",
    "c": "val4"
  },
  "key3": {
    "b": "val5",
    "c": "val6"
  }
}

Upvotes: 0

RoadRunner
RoadRunner

Reputation: 26315

An easy way is to use dict.pop() instead:

data = {
        'key1': 
            {
            'a': 'key1', 
            'b': 'val1', 
            'c': 'val2'
            }, 
        'key2': 
            {
            'a': 'key2', 
            'b': 'val3', 
            'c': 'val4'
            }, 
        'key3': 
            {  
            'a': 'key3', 
            'b': 'val5', 
            'c': 'val6'
            }
        }

for key in data:
    data[key].pop('a', None)

print(data)

Which Outputs:

{'key1': {'b': 'val1', 'c': 'val2'}, 'key2': {'b': 'val3', 'c': 'val4'}, 'key3': {'b': 'val5', 'c': 'val6'}}

The way dict.pop() works is that first checks if the key is in the dictionary, in this case "a", and it removes it and returns its value. Otherwise, return a default value, in this case None, which protects against a KeyError.

Upvotes: 7

DexJ
DexJ

Reputation: 1264

well you can simply use two dictionary's function with list comprehension pop() & itervalues()

[value.pop('a', None) for value in d.itervalues()]

print d

output > {'key3': {'c': 'val6', 'b': 'val5'}, 'key2': {'c': 'val4', 'b': 'val3'}, 'key1': {'c': 'val2', 'b': 'val1'}}

Benefit : it do not occupy extra memory. cause we are not creating new dict here

and if you are looking for simplicity @Ajax1234 answer is more descriptive

Upvotes: 1

SCB
SCB

Reputation: 6149

When you're iterating over a dictionary, dict_to_be_deleted you are only iterating over the keys. So in your second attempt, your Attribute Error is because i is the key, a string not the dictionary. How you could actually perform it would be to use .values() which iterates over the values instead.

for v in dict_to_be_deleted.values():
    del v["a"]

However, personally, instead of deleting the elements, I'd suggest following Ajax's method and building a new dictionary without the missing elements. Weird mutations like what we're doing here is an easy way to get bugs.

Upvotes: 5

Ajax1234
Ajax1234

Reputation: 71461

In this case, it may be best to filter the contents of the dictionary:

d = {
'key1': 
    {
        'a': 'key1', 
        'b': 'val1', 
        'c': 'val2'
    }, 
 'key2': 
    {
        'a': 'key2', 
        'b': 'val3', 
        'c': 'val4'
    }, 
'key3': 
    {
        'a': 'key3', 
        'b': 'val5', 
        'c': 'val6'
    }
 }
new_d = {a:{c:d for c, d in b.items() if c != 'a'} for a, b in d.items()}

Output:

{'key3': {'c': 'val6', 'b': 'val5'}, 'key2': {'c': 'val4', 'b': 'val3'}, 'key1': {'c': 'val2', 'b': 'val1'}}

Upvotes: 3

Related Questions