Search code examples
python-3.xlist-comprehensiondictionary-comprehension

Is it possible to simplify these kinds of checks on dictionary?


I have a dictionary containing lists of dictionaries and nested lists of strings. I figured out a way using comprehensions to perform checks before adding items. However, I'm not sure if this is the best, most simplified way to do this.

    my_dict = {
        'employees':[
            {
                'name':'Kevin',
                'software':[
                    {
                        'name':'soft1',
                        'modules':[
                            'mod1',
                            'mod2',
                            'mod3'
                        ]
                    },
                    {
                        'name':'soft2', 
                        'modules':[
                            'mod1',
                            'mod2',
                            'mod3'
                        ]
                    },
                    {
                        'name':'soft3', 
                        'modules':[
                            'mod1',
                            'mod2',
                            'mod3'
                        ]
                    }
                ]
            },
            {
                'name':'Bob', 
                'software':[
                    {
                        'name':'soft3', 
                        'modules':[
                            'mod4',
                            'mod5',
                            'mod6'
                        ]
                    },
                    {
                        'name':'soft4', 
                        'modules':[
                            'mod10'
                        ]
                    },
                    {
                        'name':'soft6', 
                        'modules':[
                            'mod1',
                            'mod5'
                        ]
                    },
                    {
                        'name':'soft7', 
                        'modules':[
                            'mod1',
                            'mod3',
                            'mod5'
                        ]
                    }
                ]
            }
        ]
    }
    
    new_employee_name = "Steward"
    new_software_learnt = "soft2"
    new_module_learnt = "mod20"
    
    if not new_employee_name in [_['name'] for _ in my_dict['employees']]:
        my_dict['employees'].append({'name':new_employee_name, 'software':[{"name":new_software_learnt, 'modules':[new_module_learnt]}]})
        
    new_software_learnt = "soft3"
    new_module_learnt = "mod22"
    
    if not new_software_learnt in [_['name'] for _ in [_['software'] for _ in my_dict['employees']][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]]:
        my_dict['employees'][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]['software'].append({'name':new_software_learnt, 'modules':[new_module_learnt]})
    
    new_software_learnt = "soft3"
    new_module_learnt = "mod55"
    
    if not new_module_learnt in [_['modules'] for _ in [_['software'] for _ in my_dict['employees']][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]][[_['name'] for _ in [_['software'] for _ in my_dict['employees']][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]].index(new_software_learnt)]:
        [_['modules'] for _ in [_['software'] for _ in my_dict['employees']][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]][[_['name'] for _ in [_['software'] for _ in my_dict['employees']][[_['name'] for _ in my_dict['employees']].index(new_employee_name)]].index(new_software_learnt)].append(new_module_learnt)
    
    print(my_dict['employees'])

Could anyone suggest a better more simplified approach? Perhaps there are some modules that are good in that? Should I better break down the comprehensions into separate functions to check each "level" of the dictionary?

Ultimately, this dictionary will be saved as json file.


Solution

  • As you suggest, moving the work into one or more helper functions will simplify your mainline code significantly. add_empdata() should probably be refactored further, but here is a quick and dirty example of the general idea:

    from pprint import pprint
    
    def add_empdata(empdict, empname, swname, modname):
        # find employee record if extant else create new employee record and exit
        for employee in empdict["employees"]:
            if employee["name"] == empname:
                break
        else:  # no break
            empdict["employees"].append(dict(name=empname, software=[dict(name=swname, modules=[modname])]))
            return
    
        # add software and module data for extant employee if not already in employee
        for software in employee["software"]:
            if software["name"] == swname:
                if modname not in software["modules"]:
                    software["modules"].append(modname)
                break
        else:  # no break
            employee["software"].append(dict(name=swname, modules=[modname]))
    
    new_empdata = [
        ("Steward", "soft2", "mod20"),
        ("Steward", "soft3", "mod22"),
        ("Steward", "soft3", "mod55"),
    ]
    for empname, swname, modname in new_empdata:
        add_empdata(my_dict, empname, swname, modname)
    
    pprint(my_dict['employees'])
    

    Output:

    [{'name': 'Kevin',
      'software': [{'modules': ['mod1', 'mod2', 'mod3'], 'name': 'soft1'},
                   {'modules': ['mod1', 'mod2', 'mod3'], 'name': 'soft2'},
                   {'modules': ['mod1', 'mod2', 'mod3'], 'name': 'soft3'}]},
     {'name': 'Bob',
      'software': [{'modules': ['mod4', 'mod5', 'mod6'], 'name': 'soft3'},
                   {'modules': ['mod10'], 'name': 'soft4'},
                   {'modules': ['mod1', 'mod5'], 'name': 'soft6'},
                   {'modules': ['mod1', 'mod3', 'mod5'], 'name': 'soft7'}]},
     {'name': 'Steward',
      'software': [{'modules': ['mod20'], 'name': 'soft2'},
                   {'modules': ['mod22', 'mod55'], 'name': 'soft3'}]}]