Home > OS >  Updating dictionary values using zip() in python
Updating dictionary values using zip() in python

Time:01-03

I have 4 lists (of floats), which I have extracted from a json file. I have to modify the values in these 4 lists simultaneously, depending on the first list. I am using zip() to iterate over all the 4 lists, but I am unable to update the dict values. The idea is to check the sign of the first list, if it is negative, all the values in the 4 lists have to be set to 0. Following is a simplified json format, I am using as my input -

{
   "channels": [
      {
         "name": "TTZAR1e", 
         "samples": [
            {
               "data": [0.0996781, 0.0177724, -0.00566106],
               "modifiers": [
                  {"data": [0.084338, 0.0103356, 0.010294], "type": "staterror"}, 
                  {"data": {"hi_data": [0.0996781, 0.0177724, -0.00566106], "lo_data": [0.0996781, 0.0177724, -0.00566106]}, "type": "histosys"} 
                ], 
               "name": "conv"
            }
         ]
      }            
  ]
} 

Following is what I have tried -

import json 
file = open("test1.json", 'r')
json_data = json.load(file)

for key, value in json_data.items():
    for i in value:
        for samp in i.get('samples'):
            for mod in samp.get('modifiers'):
                hi_list=[]
                lo_list=[]
                if(mod.get('type') == 'staterror'):
                    stat_list = mod.get('data')
                if(mod.get('type') == 'histosys'):
                    hi_list = mod.get('data').get('hi_data')
                    lo_list = mod.get('data').get('lo_data')
                for val, val2, val3, val4 in zip(samp.get('data'), hi_list, lo_list, stat_list):
                    if (val<0):
                        val,val2,val3,val4  = 0,0,0,0

The issue is when I print the json, I still get the negative values, the final output I am working towards is as below -

{
   "channels": [
      {
         "name": "TTZAR1e", 
         "samples": [
            {
               "data": [0.0996781, 0.0177724, 0],
               "modifiers": [
                  {"data": [0.084338, 0.0103356, 0],"type": "staterror"}, 
                  {"data": {"hi_data": [0.0996781, 0.0177724, 0], "lo_data": [0.0996781, 0.0177724, 0]}, "type": "histosys"} 
                ], 
               "name": "conv"
            }
         ]
      }            
  ]
} 

I would like to know how to update the values in the dictionary itself, I understand that changing the val in the loop, would not affect the actual dict.values themselves.

Is there a way to implement this here or any other "simpler" way for the same ?

Thank you very much !

Best, Shreya

CodePudding user response:

zip() creates a list of tuples. These tuples do not share any memory with the original lists, meaning that you have no way of mutating the inputs to zip() using what it returns.

You should store references to the lists that you want to modify, and then modify them in-place. (I will note that you should seriously consider simplifying this code, as the high nesting depth makes this code hard to read and debug.) Here's a code snippet that does that:

for key, value in json_data.items():
    for i in value:
        for samp in i.get('samples'):
            lists_to_modify = [samp.get('data')]
            for mod in samp.get('modifiers'):
                if(mod.get('type') == 'staterror'):
                    lists_to_modify.append(mod.get('data'))
                if(mod.get('type') == 'histosys'):
                    lists_to_modify.append(mod.get('data').get('hi_data'))
                    lists_to_modify.append(mod.get('data').get('lo_data'))
            for data_index in range(len(samp.get('data'))):
                if samp.get('data')[data_index] < 0:
                    for list_to_modify in lists_to_modify:
                        list_to_modify[data_index] = 0

CodePudding user response:

The inner for-loop that updates the lists is inside the loop that gets the lists. You need to take that out. Then since you only need the index of the negative number in samp.get('data'), you don't need to use zip, rather you need enumerate. Then it will work as expected:

for key, value in json_data.items():
    for i in value:
        for samp in i.get('samples'):
            for mod in samp.get('modifiers'):
                if(mod.get('type') == 'staterror'):
                    stat_list = mod.get('data')
                if(mod.get('type') == 'histosys'):
                    hi_list = mod.get('data').get('hi_data')
                    lo_list = mod.get('data').get('lo_data')
            for i, val in enumerate(samp.get('data')):
                if (val<0):
                    samp.get('data')[i] = hi_list[i] = lo_list[i] = stat_list[i] = 0

Output:

{'channels': [{'name': 'TTZAR1e',
   'samples': [{'data': [0.0996781, 0.0177724, 0],
     'modifiers': [{'data': [0.084338, 0.0103356, 0], 'type': 'staterror'},
      {'data': {'hi_data': [0.0996781, 0.0177724, 0],
        'lo_data': [0.0996781, 0.0177724, 0]},
       'type': 'histosys'}],
     'name': 'conv'}]}]}
  • Related