How do I remove certain keys from a nested dictionary in Python? - python

I'm doing this in Python 3.8 and I havent been able to fine a clean solution.
I am trying to remove any values from a nested dictionary if the value is equal to 0.
So the nested dictionary kinda looks like this:
{1: {"alert1" : 0, "alert2": 1, "alert3" : 3, "alert4": 1},
2: {"alert1" : 45, "alert2": 2, "alert3" : 0, "alert4": 54},
3: {"alert1" : 2, "alert2": 1, "alert3" : 33, "alert4": 11},
4: {"alert1" : 1, "alert2": 0, "alert3" : 2, "alert4": 0}}
And so if I want to print it or view it but only if an alert is not 0
so print(nested_dic) would look like this.
1 - alert2: 1 alert3: 3 alert4: 1
2 - alert1: 45 alert2: 2 alert4: 54
3 - alert1: 2 alert2: 1 alert3: 33 alert3: 11
4 - alert1: 1 alert3: 2
EDIT: Either delete the non zeroes or save a new dictionary without zeroes to be printed out.

If you only have one level of nesting I think using a comprehension inside a comprehension is still readable, so I would suggest this (d is your dictionary here):
>>> {k: {k_sub: v_sub for k_sub, v_sub in v.items() if v_sub != 0} for k, v in d.items()}
{1: {'alert2': 1, 'alert3': 3, 'alert4': 1},
2: {'alert1': 45, 'alert2': 2, 'alert4': 54},
3: {'alert1': 2, 'alert2': 1, 'alert3': 33, 'alert4': 11},
4: {'alert1': 1, 'alert3': 2}}
But maybe you prefer code that is more detailed and add more names so it's easier to read:
def non_zero(alerts):
return {code: value for code, value in alerts.items() if value != 0}
all_alerts = {1: {"alert1" : 0, "alert2": 1, "alert3" : 3, "alert4": 1},
2: {"alert1" : 45, "alert2": 2, "alert3" : 0, "alert4": 54},
3: {"alert1" : 2, "alert2": 1, "alert3" : 33, "alert4": 11},
4: {"alert1" : 1, "alert2": 0, "alert3" : 2, "alert4": 0}}
all_non_zero_alerts = {identifier: non_zero(alerts) for identifier, alerts in all_alerts.items()}
This does the exact same thing as before but it may be a bit more clear what the code is achieving.

My solution is to use a list comprehension. This is best for iterating and removing any unwanted items. Here's an example of how this would work:
dic = {1: {"alert1" : 0, "alert2": 1, "alert3" : 3, "alert4": 1},
2: {"alert1" : 45, "alert2": 2, "alert3" : 0, "alert4": 54},
3: {"alert1" : 2, "alert2": 1, "alert3" : 33, "alert4": 11},
4: {"alert1" : 1, "alert2": 0, "alert3" : 2, "alert4": 0}}
for key in dic:
value = dic[key]
keys = {k:v for (k, v) in value.items() if v != 0}
print(keys)
Here, the only filtering you're doing happens on that for iteration loop, where you loop through all keys if the value isn't 0.
This solution is preferable since it uses the Pythonic dictionary comprehension, which allows you to neatly iterate over each items in the individual dict in a simple line. Relative to loops, this is a more beneficial approach since Python can easily optimize list comprehensions to improve efficiency.
Variations
If you want to modify the existing dictionary, you can simply modify the key while you're iterating over it, as follows:
for key in dic:
value = dic[key]
updated = {k:v for (k, v) in value.items() if v != 0}
dic[key] = updated
If you want to make a copy, simply create another dictionary and add it:
new_dict = {}
for key in dic:
value = dic[key]
updated = {k:v for (k, v) in value.items() if v != 0}
new_dict[key] = updated
These approaches can be seen here (commented out)

Related

I am trying to add entries from list in list to dictionary present in other list

a = [ { 1:1 }, {2:2}, {3:3} ] b=[[0,25],[26,51],[52,99]]
I tried doing this:
for item in a:
for j in range(len(a)):
item.update( { "st": b[j][0] ,"et": b[j][1]} )
print("a in loop:",a )
getting this output
[{1:1,st:52,et:99},{2:2,st:52,et:99},{3:3,st:52,et:99}]
and I am expecting
[{1:1,st:0,et:25},{2:2,st:26,et:51},{3:3,st:52,et:99}]
You are doing a double loop while you should be looping once.
a = [ { 1:1 }, {2:2}, {3:3} ]
b=[[0,25],[26,51],[52,99]]
for i,v in enumerate(a):
v.update( { "st": b[i][0] ,"et": b[i][1]} )
print("a in loop:",a )
Output:
a in loop: [{1: 1, 'st': 0, 'et': 25}, {2: 2, 'st': 26, 'et': 51},
{3: 3, 'st': 52, 'et': 99}]
You need not iterate on both lists, use the index to access the other list and update your dict. Example below
a = [{1: 1}, {2: 2}, {3: 3}]
b = [[0, 25], [26, 51], [52, 99]]
[_dict.update(dict(st=b[index][0],et=b[index][1])) for index, _dict in enumerate(a)]
print(a)
Brings a result:
[{1: 1, 'st': 0, 'et': 25}, {2: 2, 'st': 26, 'et': 51}, {3: 3, 'st': 52, 'et': 99}]
Here you are looping through list a and trying to update list b values by looping with length of list b. Second loop always completes with last value of list b and hence all 'list a' dict will be appended with last element of list b.
You can use zip function to iterate 2 list at the same time.
for item1, item2 in zip(a,b):
item1.update({"st": item2[0], "et": item2[1]})
print("a in loop:",a )

How to add an existing dictionary as a nested dictionary to an already existing dictionary in python?

In python3, I have 2 dictionaries, dict1 and dict2 that are both populated with key/value pairs. I want to create a new dictionary dict3 and add both dict1 and dict2 as nested dictionaries to it. I cant BELIEVE how much time Ive wasted trying to google a solution. I find tutorial after tutorial about how to create nested dictionaries from scratch but nothing about adding an existing dictionary nested to another dictionary.
IIUC:
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3=dict(list(dict1.items())+[('dict2', dict2)])
print(dict3)
Output:
{1: 2, 3: 4, 'dict2': {5: 6, 7: 8}}
Or if you want to add the two dictionary:
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3=dict([('dict1', dict1)]+[('dict2', dict2)])
print(dict3)
#Output:
#{'dict1': {1: 2, 3: 4}, 'dict2': {5: 6, 7: 8}}
Another ways:
#first scenario
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3={**dict1}
dict3.update({'dict2':dict2})
print(dict3)
#Output:
#{1: 2, 3: 4, 'dict2': {5: 6, 7: 8}}
#second scenario
dict1={1:2,3:4}
dict2={5:6,7:8}
dict3={}
dict3.update({'dict1':dict1,'dict2':dict2})
print(dict3)
#Output:
#{'dict1': {1: 2, 3: 4}, 'dict2': {5: 6, 7: 8}}

Extract keys from a list of dicts with single key-value pairs

I have a list which is like this:
[{0: 26},
{0: 36},
{1: 1},
{0: 215},
{1: 63},
{0: 215}]
How can I extract a list of keys from it?
[0, 0, 1, 0, 1, 0]
Use dict.keys() to get keys out of a dictionary and use it in a list-comprehension like below:
lst = [{0: 26},
{0: 36},
{1: 1},
{0: 215},
{1: 63},
{0: 215}]
print([y for x in lst for y in x.keys()])
# [0, 0, 1, 0, 1, 0]
Or, this should be further simplified as:
print([y for x in lst for y in x])
Because, when you simply iterate through dictionary like for y in x, you are actually iterating through keys of the dictionary.
Use dict.keys to extract the keys of each of the dict, convert to a list, and then extract the first element
>>> lst = [{0: 26}, {0: 36}, {1: 1}, {0: 215}, {1: 63}, {0: 215}]
>>> [list(d.keys())[0] for d in lst]
[0, 0, 1, 0, 1, 0]
Alternatively, you can use list comprehension as below
>>> [k for d in lst for k in d.keys()]
[0, 0, 1, 0, 1, 0]
I suggest you to simply iterate over the list of dictionaries, and to iterate over the keys of each dictionary, using list comprehension as follows:
myList = [{0: 26}, {0: 36}, {1: 1}, {0: 215}, {1: 63}, {0: 215}]
newList = [k for d in myList for k in d]
print(newList) # [0, 0, 1, 0, 1, 0]
Those are the keys so you would use the dict.keys() method:
L = [{0: 26},
{0: 36},
{1: 1},
{0: 215},
{1: 63},
{0: 215}]
L2 = [list(d.keys())[0] for d in L]
use keys() function of dict().
a = [{0: 26}, {0: 36}, {1: 1}, {0: 215}, {1: 63}, {0: 215}]
keys = list(a.keys()[0])
vaues = (a.values()[0])
Cheers!
you can do it this way :
list = [list(d.keys())[0] for d in originalList] # originalList is the first list you posted
Here's the output : [0, 0, 1, 0, 1, 0]
You can use dict.keys and itertools.chain to build a list of all keys:
from itertools import chain
w = [{0: 26},
{0: 36},
{1: 1},
{0: 215},
{1: 63},
{0: 215}]
keys = list(chain.from_iterable(map(dict.keys, w)))
OR try the below code, using map:
lod=[{0: 26},
{0: 36},
{1: 1},
{0: 215},
{1: 63},
{0: 215}]
print(list(map(lambda x: list(x.keys())[0])))

How to get and modify the value of nested dictionary?

I have this kind of dictionary in python:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
I want to modify all of the value in the key by whatever value I want. Let's say 100, the methods I tried are below:
counter = 1
print(x)
for key,anotherKey in x.items():
while counter not in x[key]:
counter+=1
while counter in x[key]:
x[key][counter] = 100
counter+=1
counter =0
Which got the result below:
{'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 6},
'is': {1: 100},
'something': {90: 100,92: 3}}
I know why this is happening it's because the loop doesn't consider if the differences is more than 1 which in this case in 'this' : where the differences from 2 to 7 is more than 1. However I don't know how to solve this.
You can iterate via a nested for loop:
x = {'test': {1: 2, 2: 4, 3: 5},
'this': {1: 2, 2: 3, 7: 6},
'is': {1: 2},
'something': {90: 2,92:3}}
for a in x:
for b in x[a]:
x[a][b] = 100
print(x)
{'is': {1: 100},
'something': {90: 100, 92: 100},
'test': {1: 100, 2: 100, 3: 100},
'this': {1: 100, 2: 100, 7: 100}}
Or for a new dictionary you can use a dictionary comprehension:
res = {a: {b: 100 for b in x[a]} for a in x}
You can use dictionary comprehension in this way:
{a: {b:100 for b in d} for (a,d) in x.items()}

Python dict of dict setting values missmatch

Hi can anyone explain why we have the following behavior:
>>> k = [0.5, 1, 2]
>>> m = [0.5, 1, 2]
>>> dict1 = dict.fromkeys(k, dict.fromkeys(m, 0))
>>> dict1
{0.5: {0.5: 0, 1: 0, 2: 0}, 1: {0.5: 0, 1: 0, 2: 0}, 2: {0.5: 0, 1: 0, 2: 0}}
>>> dict1[0.5][0.5]= 4.5
>>> dict1
{0.5: {0.5: 4.5, 1: 0, 2: 0}, 1: {0.5: 4.5, 1: 0, 2: 0}, 2: {0.5: 4.5, 1: 0, 2: 0}}
>>> dict2 = {0.5: {0.5: 0, 1: 0, 2: 0}, 1: {0.5: 0, 1: 0, 2: 0}, 2: {0.5: 0, 1: 0, 2: 0}}
>>> dict2[0.5][0.5] = 4.5
>>> dict2
{0.5: {0.5: 4.5, 1: 0, 2: 0}, 1: {0.5: 0, 1: 0, 2: 0}, 2: {0.5: 0, 1: 0, 2: 0}}
so in the first case whenever I try to change a value of dict1 all the values with the same second key are changing (e.g dict1[0.5][0.5]=4.5 will also change dict1[1][0.5] for some reason).
I haven't found a good dupe target, although this general issue is common:
Because dict.fromkeys(m, 0) runs once when the function is called, and then puts the same dictionary in every value for dict.fromkeys(k, dict.fromkeys(m, 0)). You can check this by doing for dct in dict1: print id(dict1[dct]) they will all be the same id, eg. the same object:
>>> for dct in dict1: print id(dict1[dct])
140401847695352
140401847695352
140401847695352
This happens because parameters are only evaluated once, when the function is called... so dict.fromkeys will put the same value (whatever that may be) in every key. It is equivalent to:
default_dct = dict.fromkeys(m, 0)
dict1 = dict.fromkeys(k, default_dct)
Instead, you can use a dictionary comprehension:
dict1 = {key: {ikey: 0 for ikey in m} for key in k}
or, via copying:
inner_dct = dict.fromkeys(m, 0)
dict1 = {}
for key in k:
dict1[key] = inner_dct.copy()
Both of which yield different values:
>>>for dct in dict1: print id(dict1[dct])
140401847695352
140401847646200
140401847644240
Only one sub-dictionary was ever created. What you have now is that dictionary itself accessible in multiple ways.
dict[0.5] and dict[1] refer to the same dictionary (and not copies of it).
One way to achieve what you want to do is to use a dict comprehension:
dict1 = {k_outer: {k_inner:0 for k_inner in m} for k_outer in k}
This creates a new nested dict for each key, thereby avoiding the problem of them all accessing the same nested dict.

Categories