Abhishek Kulkarni
Abhishek Kulkarni

Reputation: 3818

Python Generate a dynamic dictionary from the list of keys

I do have a list as given below -

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
value1 = "Roger"

How can I generate dynamic dictionary which can be retrieved as below -

mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value

The list could be anything; Variable Length or consisting of "N" number of elements unknown to me...

Now I do have another list, so that My dictionary should be updated accordingly

keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
value2 = 25

i.e. If Keys "Person", "Male", "Boy", "Student", "id_123" already exists, the new key "age" should be appended ...

Upvotes: 8

Views: 34275

Answers (7)

Rao
Rao

Reputation: 892

Perhaps you could subclass dict:

class ChainDict(dict):
    def set_key_chain(self, keyList, value):
        t = self
        for k in keyList[:-1]:
            t = t.setdefault(k, {})
        t.setdefault(keyList[-1], value)

c = ChainDict()
c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Name'], 'Roger')
print c
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Name': 'Roger'}}}}}}

c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Age'], 25)
print c
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 25,
      'Name': 'Roger'}}}}}}

Upvotes: 3

Torben Klein
Torben Klein

Reputation: 3116

Use tuple(keyList1) as key. (tuples are immutable and therefore can be dict keys).

You will have a world of headache with the nested dict approach. (nested loops for enumeration, legacy data when the hierarchy needs to change, etc.).

On a second thought, maybe you should define a person class

class Person(object):
    gender = "Male"
    group = "Student"
    id = 123
    Name = "John Doe"

then use a list of all persons and filter with e.g.

male_students = [s for s in  ALL_PERSONS where s.gender=="Male" and s.group="Student"]

... for <= 10000 students you should be fine performancewise.

Upvotes: 0

roman
roman

Reputation: 117370

I'm just learning python, so my code could be not very pythonic, but here's my code

d = {}

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
value1 = "Roger"
value2 = 3

def insert(cur, list, value):
    if len(list) == 1:
        cur[list[0]] = value
        return
    if not cur.has_key(list[0]):
        cur[list[0]] = {}
    insert(cur[list[0]], list[1:], value)

insert(d, keyList1, value1)
insert(d, keyList2, value2)

{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 3, 'Name': 'Roger'}}}}}}

Upvotes: 8

John La Rooy
John La Rooy

Reputation: 304137

>>> mydict = {}
>>> keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"]
>>> value1 = "Roger"
>>> reduce(lambda x, y: x.setdefault(y, {}), keyList1, mydict)
{}
>>> mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1

You can also do it in one step like this

>>> keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"]
>>> value2 = 25
>>> reduce(lambda x,y: x.setdefault(y,{}), keyList2[:-1], mydict).update({keyList2[-1]: value2})

Upvotes: -2

Shruti Joshi
Shruti Joshi

Reputation: 173

I am trying to dealing with similar stuff, so I can suggest some guidelines, but again I am naive in Python, so this is just a guideline...

you have a list of keys , so you can definitely start with a loop iterating for each value and then assign the value

like

for i in keylist:
if type(keylist[i]) == dict:
        do something
    else:
        keylist[i] = {}

in the do something, you need to increment i and change index to [i][i+1] and then follow the same untill i+n = len(keylist)

Upvotes: 0

nneonneo
nneonneo

Reputation: 179392

You can do this by making nested defaultdicts:

from collections import defaultdict

def recursive_defaultdict():
    return defaultdict(recursive_defaultdict)

def setpath(d, p, k):
    if len(p) == 1:
        d[p[0]] = k
    else:
        setpath(d[p[0]], p[1:], k)

mydict = recursive_defaultdict()

setpath(mydict, ["Person", "Male", "Boy", "Student", "id_123", "Name"], 'Roger')

print mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"]
# prints 'Roger'

This has the nice advantage of being able to write

mydict['a']['b'] = 4

without necessarily having to use the setpath helper.

You can do it without recursive defaultdicts too:

def setpath(d, p, k):
    if len(p) == 1:
        d[p[0]] = k
    else:
        setpath(d.setdefault(p[0], {}), p[1:], k)

Upvotes: 4

Steve Barnes
Steve Barnes

Reputation: 28370

Create your own class derived from dict where the init method takes a list and a single value as inputs and iterate through the list setting the keys to value, define an update method that takes a list and a new value and for each item that is not already a key set it to the new value, (assuming that is what you need).

Forget the idea of

mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1`

as it is confusing with subindexes.

Upvotes: 1

Related Questions