I do have a list as given below -
keyList1 = [\"Person\", \"Male\", \"Boy\", \"Student\", \"id_123\", \"Name\"]
value1 = \"Roger\"
How can I ge
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'}}}}}}
You can do this by making nested defaultdict
s:
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 defaultdict
s too:
def setpath(d, p, k):
if len(p) == 1:
d[p[0]] = k
else:
setpath(d.setdefault(p[0], {}), p[1:], k)
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.
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.
>>> 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})
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'}}}}}}