0

My objective is to add a value to a list that exists in a nested dictionary.

I created a nested dictionary recursively using a method I wrote. I need this method to create the dictionary because it can have any number of "dimensions".

def create_nested_dict(dimensions):
    if len(dimensions) == 1:
        return dict.fromkeys(range(dimensions[0]), [])
    else:
        return dict.fromkeys(range(dimensions[0]), create_nested_dict((dimensions[1:])))

For example, d = create_nested_dict([2, 3]) generates a dictionary d with keys first in range(2) and then in range(3). Like this:

{0: {0: [], 1: [], 2: []}, 1: {0: [], 1: [], 2: []}}

However, now I need to add values to the lists the dictionary contains.

If I try to append a value to the list in position [0][1] like this (d[0][1]).append(3), the value is appended in all the lists:

{0: {0: [3], 1: [3], 2: [3]}, 1: {0: [3], 1: [3], 2: [3]}}

If I use the splat operator instead d[0][1] = [*d[0][1], 3]:

I get this result:

{0: {0: [], 1: [3], 2: []}, 1: {0: [], 1: [3], 2: []}}

which is not what I need either.

The expected result is to get the value appended to just the position [0][1]:

{0: {0: [], 1: [3], 2: []}, 1: {0: [], 1: [], 2: []}}

I don't know if this behavior has something to do with the method I used to create the dictionary or the keys being ints or if I'm just storing incorrectly.

Edit: I tried changing the ints by strings and the behavior didn't change.

6659081
  • 381
  • 7
  • 21

2 Answers2

0

When you do dict.fromkeys(range(dimensions[0]), create_nested_dict((dimensions[1:]))), you're assigning the same dict as the value for all the keys. Since it is the same dict (i.e. it is only 1 Python object under the hood, and each entry in the dict is a reference to this same object), changing one will change them all.

You should create a fresh dictionary each time, you can easily do this by using a dict comprehension:

def create_nested_dict(dimensions):
    if len(dimensions) == 1:
        return {k: [] for k in range(dimensions[0])}
    else:
        return {k: create_nested_dict(dimensions[1:]) for k in range(dimensions[0])}
dogman288
  • 613
  • 3
  • 9
  • I think the last part should be "for k in range(dimensions[0])", if you edit that, I'll consider this the right answer. – 6659081 Jul 10 '20 at 03:37
0

Here is how:

def create_nested_dict(dimensions):
    if len(dimensions) == 1:
        return {k: [] for k in range(dimensions[0])}
    return {k: create_nested_dict(dimensions[1]) for k in range(dimensions[1])}

Note that we don't need an extra else statement in the function. the return statements are enough.

Red
  • 26,798
  • 7
  • 36
  • 58