I think what you're trying to do is make a nested dictionary. If I understand your input correctly, your code could be fixed just by setting report_dict[row[0]] to an empty dict, by changing
report_dict[row[0]] = row[3]
to
report_dict[row[0]] = {}
This would make the next line,
report_dict[row[0]][row[3]] = row[1]
add the key row[3] with value row[1] to the dictionary report_dict[row[0]]. This would give us:
report_dict = {row[0]: {row[3]: row[1]}, ...}
which I think is your expected output.
Answer from CDJB on Stack OverflowVideos
A nested dict is a dictionary within a dictionary. A very simple thing.
Copy>>> d = {}
>>> d['dict1'] = {}
>>> d['dict1']['innerkey'] = 'value'
>>> d['dict1']['innerkey2'] = 'value2'
>>> d
{'dict1': {'innerkey': 'value', 'innerkey2': 'value2'}}
You can also use a defaultdict from the collections package to facilitate creating nested dictionaries.
Copy>>> import collections
>>> d = collections.defaultdict(dict)
>>> d['dict1']['innerkey'] = 'value'
>>> d # currently a defaultdict type
defaultdict(<type 'dict'>, {'dict1': {'innerkey': 'value'}})
>>> dict(d) # but is exactly like a normal dictionary.
{'dict1': {'innerkey': 'value'}}
You can populate that however you want.
I would recommend in your code something like the following:
Copyd = {} # can use defaultdict(dict) instead
for row in file_map:
# derive row key from something
# when using defaultdict, we can skip the next step creating a dictionary on row_key
d[row_key] = {}
for idx, col in enumerate(row):
d[row_key][idx] = col
According to your comment:
may be above code is confusing the question. My problem in nutshell: I have 2 files a.csv b.csv, a.csv has 4 columns i j k l, b.csv also has these columns. i is kind of key columns for these csvs'. j k l column is empty in a.csv but populated in b.csv. I want to map values of j k l columns using 'i` as key column from b.csv to a.csv file
My suggestion would be something like this (without using defaultdict):
Copya_file = "path/to/a.csv"
b_file = "path/to/b.csv"
# read from file a.csv
with open(a_file) as f:
# skip headers
f.next()
# get first colum as keys
keys = (line.split(',')[0] for line in f)
# create empty dictionary:
d = {}
# read from file b.csv
with open(b_file) as f:
# gather headers except first key header
headers = f.next().split(',')[1:]
# iterate lines
for line in f:
# gather the colums
cols = line.strip().split(',')
# check to make sure this key should be mapped.
if cols[0] not in keys:
continue
# add key to dict
d[cols[0]] = dict(
# inner keys are the header names, values are columns
(headers[idx], v) for idx, v in enumerate(cols[1:]))
Please note though, that for parsing csv files there is a csv module.
UPDATE: For an arbitrary length of a nested dictionary, go to this answer.
Use the defaultdict function from the collections.
High performance: "if key not in dict" is very expensive when the data set is large.
Low maintenance: make the code more readable and can be easily extended.
Copyfrom collections import defaultdict
target_dict = defaultdict(dict)
target_dict[key1][key2] = val
If you are using python 3.5 or greater you can merge your dictionaries using the following syntax:
appointment1 = { 'soccer' : {
'day' : 20,
'month' : 'april'
}
}
appointment2 = { 'soccer' : {
'day' : 20,
'month' : 'april'
},
'gym' : {
'day' : 5,
'month' : 'may'
}
}
appointment = {**appointment1,**appointment2}
If the dicts already exist you might look at dict.update().
Short answer is do this:
>>> appointment = { 'soccer' : { 'day': 20, 'month': 'april' } }
>>> appointment2 = { 'gym' : { 'day': 5, 'month': 'may' } }
>>> appointment.update(appointment2)
>>> appointment
{'gym': {'day': 5, 'month': 'may'}, 'soccer': {'day': 20, 'month': 'april'}}
But if you're making these dicts it makes more sense to just add new entries in the usual way (See: Add new keys to a dictionary?):
>>> appointment = { 'soccer' : { 'day': 20, 'month': 'april' } }
>>> appointment['gym'] = {'day': 5, 'month': 'may'}
>>> appointment
{'gym': {'day': 5, 'month': 'may'}, 'soccer': {'day': 20, 'month': 'april'}}
The problem is that mydict is not simply a collection of nested dictionaries. It contains a list as well. Breaking up the definition helps clarify the internal structure:
dictlist = [{'key1':'value1','key2':'value2'},
{'key1':'value3','key2':'value4'}]
resultdict = {'result':dictlist}
mydict = {'a':resultdict}
So to access the innermost values, we have to do this. Working backwards:
mydict['a']
returns resultdict. Then this:
mydict['a']['result']
returns dictlist. Then this:
mydict['a']['result'][0]
returns the first item in dictlist. Finally, this:
mydict['a']['result'][0]['key1']
returns 'value1'
So now you just have to amend your for loop to iterate correctly over mydict. There are probably better ways, but here's a first approach:
for inner_dict in mydict['a']['result']: # remember that this returns `dictlist`
for key in inner_dict:
do_something(inner_dict, key)
I'm not fully sure what you're trying to do, but I think itertools.count would be able to help here.
>>> c = itertools.count()
>>> c.next()
0
>>> c.next()
1
>>> c.next()
2
>>> c.next()
3
... and so on.
Using this, you can keep incrementing the value that you want to use in your dicts
Hope this helps
In python, append is only for lists, not dictionaries.
This should do what you want:
d['A']['b'] = 3
Explanation: When you write d['A'] you are getting another dictionary (the one whose key is A), and you can then use another set of brackets to add or access entries in the second dictionary.
You're looking for the update method:
d['A'].update({'b':3})
You told your code to assign newly created dict to key e[0]. It's always replaced blindly and it does not look at previously stored value.
Instead you need something like:
for e in keyList:
if e[0] not in nested_dict:
nested_dict[e[0]] = {}
nested_dict[e[0]].update({e[2] : e[3:]})
If conditional is required to handle 'first key' case. Alternatively defaultdict can be used.
from collections import defaultdict
nested_dict = defaultdict(dict)
for e in keyList:
nested_dict[e[0]].update({e[2] : e[3:]})
Great answer from @ŁukaszRogalski!
Just as an addition, without defaultdict, you can use setdefault:
keyList = [('A B 10'), ('A D 15')]
nested_dict = {}
for e in keyList:
rootkey = nested_dict.setdefault(e[0], {})
rootkey.update({e[2] : e[4:]})
print(nested_dict) # {'A': {'B': '10', 'D': '15'}}
When you do aDict[k], you already got the value which is dict and then you assign the temp to the specific key of the dict.
aDict = { 'id' :
{'name': None },
'id2':
{'foo':None}
}
for k, v in aDict.items():
temp = [1,2,3,4]
for keys in v.keys():
aDict[k][keys] = temp
Output
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': [1, 2, 3, 4]}}
For any arbitrary dictionary of dictionaries (no matter how deep it is), this works:
def go_deeper(aDict):
for k, v in aDict.items():
if v is None:
aDict[k] = temp
else:
go_deeper(v)
return aDict
Usage:
>>> temp = [1,2,3,4]
>>> go_deeper(aDict)
For example, for input:
aDict = { 'id' :
{'name': None },
"id2" :
{"foo":
{'bar': None }
}
}
the above code returns:
{'id': {'name': [1, 2, 3, 4]}, 'id2': {'foo': {'bar': [1, 2, 3, 4]}}}