2

I would like to write to a dictionary with a 'list-path'. I have:

container = {}
path = ['foo', 'bar']
data = [1, 2, 3]

And would like to get

container = {
    'foo' : {
        'bar' : [1, 2, 3]
    }
}

To read, I am very enthusiastic about this answer, which says that to read:

data = functools.reduce(operator.getitem, path, container)

But now I'm not managing to get the opposite right...

(I guess one could use recursion, but a one-line solution seems near!)

Almog
  • 452
  • 1
  • 7
  • 13
Tom de Geus
  • 5,625
  • 2
  • 33
  • 77
  • @jdaz Thanks! Maybe I'm naive, but those answer tell me how to build the nested dictionary (to build `container`) but not yet how to write `data` to it. Also... A one-liner would be nice! – Tom de Geus Nov 09 '20 at 17:54
  • Problem with reduce is that it only works for functions that accept two parameters, `operator.setitem` requires 3 parameters (container, index, value). I'll scratch my head a bit more... – scotty3785 Nov 09 '20 at 17:58
  • 1
    Tom, you can change the one-liner answer in that question to just use `data` as the initial object for `reduce`: `functools.reduce(lambda x, y: {y: x}, path[::-1], data)` – jdaz Nov 09 '20 at 18:20
  • Amazing @jdaz ! – Tom de Geus Nov 09 '20 at 20:08

1 Answers1

3

This isn't a one liner, but I changed this answer a bit so it would add the data to the last element.

path = ['foo','bar']
data = [1,2,3]
container = {}
for key in reversed(path):
    if (key == path[-1]):
        container = {key: data}
    else:
        container = {key: container}

This is the output: {'foo': {'bar': [1, 2, 3]}}

Edit: Nevermind, I found a one liner based on this answer

import functools
path = ['foo','bar']
data = [1,2,3]
container = functools.reduce(lambda x,y:{y:x},path[:-1],{path[-1]: data})
Axiumin_
  • 2,107
  • 2
  • 15
  • 24