0

I'm trying update update the value of a nested dictionary within a for loop, so it doesn't generate a new dictionary every time, I'm pretty new to traversing nested structures so bear with me. Each value is located in a list:

My list:

id_list = ['asf245', 'kjb456', '235sdg']

My dictionary:

temp = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "abc123"}}], "limit": 20}}

Ideally I would append each update dictionary to a dataframe and then update it with the new value:

Ideal output:

    temp = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "asf245"}}], "limit": 20}}

    temp = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "kjb456"}}], "limit": 20}} 

    temp = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "235sdg"}}], "limit": 20}}

Where temp gets appended to a dataframe every iteration then gets overwritten with the new value:

I've tried:

import collections

def update(d, u):

    for k, v in u.items():
        if isinstance(v, collections.Mapping):
            d[k] = update(d.get(k, {}), v)
        else:
            d[k] = v
    return d

print(update(temp, 'Apples')) <- "run this through a loop"

But running this through a visualizer I can see that it doesn't go deep enough, and I don't truly have a good understanding of it, if anyone could explain it that would be awesome.

Sebastian Goslin
  • 477
  • 1
  • 3
  • 22
  • it looks like your function declaration is wrong, since `u` is a `string`, how can it have a method called `items`? – gold_cy Jun 12 '19 at 15:48
  • Thats the error I got, its expecting another dictionary and I have a list, I got this function from [here](https://stackoverflow.com/questions/3232943/update-value-of-a-nested-dictionary-of-varying-depth), I'm not sure of the methodology behind it – Sebastian Goslin Jun 12 '19 at 15:50
  • so what is the expected output, a list of dictionaries? – gold_cy Jun 12 '19 at 15:53
  • @aws_apprentice ideally the updated dictionaries get appended to a dataframe, but that part I can handle, I just need to know how to traverse and manipulate nested dictionaries. – Sebastian Goslin Jun 12 '19 at 15:58

2 Answers2

1

Here. The result of the function is a list of dicts (with modified id)

import copy


def clone_dict(d, ids):
    result = []
    for id in ids:
        clone = copy.deepcopy(d)
        clone['ent']['attributes'][0]['ent']['id'] = id
        result.append(clone)
    return result


temp = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "abc123"}}], "limit": 20}}
ids = ['x', 'y', 'z']

print(clone_dict(temp, ids))

output

[{'ent': {'attributes': [{'ent': {'id': 'x'}}], 'type': 'IDN', 'limit': 20}}, {'ent': {'attributes': [{'ent': {'id': 'y'}}], 'type': 'IDN', 'limit': 20}}, {'ent': {'attributes': [{'ent': {'id': 'z'}}], 'type': 'IDN', 'limit': 20}}]

A generic approach below

import copy


def clone_dict(src_dict, values_to_inject, path_elements):
    """ Clone a dict N times and replace a nested field

    :param src_dict: Used as 'template'
    :param values_to_inject: List of values to inject
    :param path_elements: List of path elements. Used in dict navigation
    :return: A list of cloned modified dicts
    """
    result = []
    for value in values_to_inject:
        clone = copy.deepcopy(src_dict)
        temp = clone[path_elements[0]]
        for path_element in path_elements[1:-1]:
            temp = temp[path_element]
        temp[path_elements[-1]] = value
        result.append(clone)
    return result


src_dict = {"ent": {"type": "IDN", "attributes": [{"ent": {"id": "abc123"}}], "limit": 20}}
values_to_inject = ['x', 'y', 'z']
path_elements = ['ent', 'attributes', 0, 'ent', 'id']

print(clone_dict(src_dict, values_to_inject, path_elements))
balderman
  • 22,927
  • 7
  • 34
  • 52
1

Here is a more generic solution involving recursion. It takes a dictionary to update, the key to update, and the value that you want to update.

def update(to_update, key, val):
    for k, v in to_update.items():
        if k == key:
            to_update[k] = val
        else:
            if isinstance(v, dict):
                update(v, key, val)
            elif isinstance(v, list):
                for item in v:
                    if isinstance(item, (dict, list)):
                        update(item, key, val)
                    else:
                        continue
            else:
                continue
    return to_update


for id_ in id_list:
    new = update(temp, 'id', id_)
    print(new)

{'ent': {'type': 'IDN', 'attributes': [{'ent': {'id': 'asf245'}}], 'limit': 20}}
{'ent': {'type': 'IDN', 'attributes': [{'ent': {'id': 'kjb456'}}], 'limit': 20}}
{'ent': {'type': 'IDN', 'attributes': [{'ent': {'id': '235sdg'}}], 'limit': 20}}
gold_cy
  • 13,648
  • 3
  • 23
  • 45