Reputation: 143
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
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
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
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
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
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