KeyError: 'name' Why can't I use 'name'? - python

I wanna make a dictionary has name's key & data.In views.py I wrote
data_dict ={}
def try_to_int(arg):
try:
return int(arg)
except:
return arg
def main():
book4 = xlrd.open_workbook('./data/excel1.xlsx')
sheet4 = book4.sheet_by_index(0)
data_dict_origin = OrderedDict()
tag_list = sheet4.row_values(0)[1:]
for row_index in range(1, sheet4.nrows):
row = sheet4.row_values(row_index)[1:]
row = list(map(try_to_int, row))
data_dict_origin[row_index] = dict(zip(tag_list, row))
if data_dict_origin['name'] in data_dict:
data_dict[data_dict_origin['name']].update(data_dict_origin)
else:
data_dict[data_dict_origin['name']] = data_dict_origin
main()
When I printed out data_dict,it is
OrderedDict([(1, {'user_id': '100', 'group': 'A', 'name': 'Tom', 'dormitory': 'C'}), (2, {'user_id': '50', 'group': 'B', 'name': 'Blear', 'dormitory': 'E'})])
My ideal dictionary is
dicts = {
Tom: {
'user_id': '100',
'group': 'A',
'name': 'Tom',
'dormitory': 'C'
},
Blear: {
},
}
How should I fix this?What should I write it?

The code is using the wrong key in the dictionary. The keys are 1, 2, and do not have the name key. You can use this code instead:
for value in data_dict.values():
if value['name'] in data_dict:
data_dict[value['name']].update(value)
else:
data_dict[value['name']] = value

Your data_dict_origin has numbers as keys and dicts as values (which technically makes it a sparse array of dicts). The "name" key exists in those dicts, not in your data_dict.

Related

Adding selective elements of one dictionary to another

I have a list as:
my_list = ["10", "12", "32", "23"]
and a dictionary as:
my_dict = {
'one': {'index': 0, 'sec_key': 'AB', 'id': '10'},
'two': {'index': 0, 'sec_key': 'CD', 'id': '12'},
'three': {'index': 0, 'sec_key': 'EF', 'id': '32'}
}
I want to keep a dictionary say final_dict which will have content of my_dict only if the id is present in my_list. I tried to do that by:
sf_dict = dict()
for list_id in my_list:
for key, value in my_dict.items():
if list_id == value['id']:
print("Values : {} {} {}".format(value['index'], value['sec_key'], value['id']))
sf_dict[key] = key
sf_dict[key]['index'] = value['index']
sf_dict[key]['sec_key'] = value['sec_key']
sf_dict[key]['id'] = value['id']
print(sf_dict)
I'm able to print the values but the assigning of those values is failing due to the error as:
TypeError: 'str' object does not support item assignment
Where am I making mistake?
You can use a dictionary comprehension to loop over your my_dict and check if the value stored in id is in your list.
my_list = ["10", "12", "32", "23"]
my_dict = {
'one': {'index': 0, 'sec_key': 'AB', 'id': '10'},
'two': {'index': 0, 'sec_key': 'CD', 'id': '12'},
'three': {'index': 0, 'sec_key': 'EF', 'id': '32'}
}
result = {key:value for key, value in my_dict.items() if value['id'] in my_list}
#{'one': {'index': 0, 'sec_key': 'AB', 'id': '10'}, 'two': {'index': 0, 'sec_key': 'CD', 'id': '12'}, 'three': {'index': 0, 'sec_key': 'EF', 'id': '32'}}
my_list = ["10"]
#{'one': {'index': 0, 'sec_key': 'AB', 'id': '10'}}
The already given answers should do the trick, altough maybe it is important to get why your approach isn't right.
The problem with what you did is that when you do sf_dict[key] = key, you're setting the value of the dictionary for the key key with the value key. But key is a string, thus, when you later try sf_dict[key]['index'] = value['index'] it tells you that you cannot assign on top a string.
Try to remove these lines
sf_dict[key]['index'] = value['index']
sf_dict[key]['sec_key'] = value['sec_key']
sf_dict[key]['id'] = value['id']
and simply replace them with sf_dict[key] = value. This way, when you find the id you're searching for, you assign all the dictionary at once to the corresponding key.
Here is one solution:
final_dict={}
for i in my_dict:
if my_dict[i]['id'] in my_list:
final_dict[i]=my_dict[i]
Example:
my_list = ["10", "32", "23"]
Output:
print(final_dict)
{'one': {'index': 0, 'sec_key': 'AB', 'id': '10'}, 'three': {'index': 0, 'sec_key': 'EF', 'id': '32'}}
for list_id in my_list:
for key, value in my_dict.items():
if list_id == value['id']:
print("Values : {} {} {}".format(value['index'], value['sec_key'], value['id']))
sf_dict[key] = {'index':value['index'],'sec_key':value['sec_key'],'id':value['id']}
print(sf_dict)
the code should be like this.
#problem is here
sf_dict[key] = key
above line means sf_dict = {'one': 'one'} for example
so next lines mean 'one'['anything'] =
so using index to assign into str is not allowed.
better solution is already answered above, just pointing issue in exist code

creating a dictionary by partitioning a dictionary with new keys in python

I have the a dictionary like this:
{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"}
I want to create another list as follows:
[{"label":{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"},"value":
{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"}}]
I have tried some methods with .items() but none of them gives the desired result.
Is that what you want?
dict_ = {"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"}
output = [{"label": dict_ , "value": dict_ }]
print(output)
[{"label":{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"},"value":
{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"}}] == [{"label": dict_ , "value": dict_ }]
Gives True
Following my comment, below is the code I would go through assuming key and output:
# Could be the keys would get from somewhere
vals = ["1","2","3","4"]
# Probably same coming from external sources
example_op =
{"Topic":"text","title":"texttitle","abstract":"textabs","year":"textyear","authors":"authors"}
#Global list
item_list = []
temp_dict = {}
for key in vals:
temp_dict[key] = example_op
item_list.append(temp_dict)
Final output of the list would be as:
Out[9]:
[{'1': {'Topic': 'text',
'title': 'texttitle',
'abstract': 'textabs',
'year': 'textyear',
'authors': 'authors'},
'2': {'Topic': 'text',
'title': 'texttitle',
'abstract': 'textabs',
'year': 'textyear',
'authors': 'authors'},
'3': {'Topic': 'text',
'title': 'texttitle',
'abstract': 'textabs',
'year': 'textyear',
'authors': 'authors'},
'4': {'Topic': 'text',
'title': 'texttitle',
'abstract': 'textabs',
'year': 'textyear',
'authors': 'authors'}}]

Update a list of Dict based on another Dict

I have a dict as follows.
dict = {'P': ['Demo'], 'Q': ['PMS']}
And I have a list of Dict as follows.
all = [{'Name': 'PMS'}, {'Name': 'Demo'}]
I need to have the dict's respective value in all as bellow.
new_list = [{'Name': 'PMS','Code': 'Q'}, {'Name': 'Demo','Code': 'P'}]
In this specific case, given that the values are just strings and therefore hashable objects, you can use a dictionary of reverse mappings. Be aware that it could not be used if the values were not hashable.
dct = {'P': ['Demo'], 'Q': ['PMS']}
all = [{'Name': 'PMS'}, {'Name': 'Demo'}]
reverse_mapping = {v[0]:k for k, v in dct.items()}
new_list = [d.copy() for d in all]
for d in new_list:
d['Code'] = reverse_mapping[d['Name']]
print(new_list)
This gives:
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]
dct = {'P': ['Demo'], 'Q': ['PMS']}
all_ = [{'Name': 'PMS'}, {'Name': 'Demo'}]
out = [dict(**l, Code=next(k for k, v in dct.items() if l['Name'] in v)) for l in all_]
print(out)
Prints:
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]
Or: you can make temporary dictionary:
tmp = {v[0]:k for k, v in dct.items()}
out = [dict(**l, Code=tmp[l['Name']]) for l in all_]
print(out)
You could make an inverted dictionary of codes, then go through the list of dictionaries and add the codes in:
codes = {"P": ["Demo"], "Q": ["PMS"]}
lst = [{"Name": "PMS"}, {"Name": "Demo"}]
inverted_codes = {value: key for key, values in codes.items() for value in values}
# {'Demo': 'P', 'PMS': 'Q'}
for dic in lst:
code = dic["Name"]
dic["Code"] = inverted_codes[code]
print(lst)
Output
[{'Name': 'PMS', 'Code': 'Q'}, {'Name': 'Demo', 'Code': 'P'}]

Change value in dictionary

I would like to know how I can change a value in a dictionary using list of keys and 1 value
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
string1 = 'bob.name.first=Bob'
string1 = string.split('=')
string2 = string1[0].split('.')
string2.append(string[1])
Here I end up with a list of 4 items, the first 3 are keys and the last is the value.
How can I use this given list to change the value in my_dict considering that the given list keys number can be changed for example if I want to change bob.job=QA
You can write:
string1 = 'bob.name.first=Bob'
string1,string2 = string1.split('=')
string1 = string1.split('.')
my_dict[string1[0]][string1[1]][string1[2]] = string2
I suppose the following function is what you are looking for, it works with any number of keys and creates intermediates dictionaries if not exist yet.
d = {
'bob': {
'name': {
'first': 'FirstName',
'last': 'LastName'
},
'job': 'Developer'
}
}
def update_dict_by_expr(d, expr):
keys_value = expr.split('=')
keys = keys_value[0].split('.')
value = keys_value[1]
item = d
while len(keys) > 1:
key = keys.pop(0)
if key not in item:
item[key] = {}
item = item[key]
key = keys[0]
item[key] = value
print(d)
update_dict_by_expr(d, 'bob.name.first=Bob Junior')
update_dict_by_expr(d, 'bob.name.birth.date=01/01/2017')
update_dict_by_expr(d, 'bob.name.birth.place=NYC')
print(d)
You want a dict with keys that can be accessed as attributes. You can achieve that by subclassing dict class, and add support for your need. I think this is more pythonic solution as it is much more intuative:
class MyDict(dict):
def __getattr__(self, attr):
return self[attr] if attr in self.keys() else None
def __setattr__(self, attr, value):
self[attr] = value
my_dict = MyDict({
'bob': MyDict(
{'name':
MyDict({'first': 'FirstName', 'last': 'LastName'}),
'job':'Developer'})})
>>> my_dict.bob
{'job': 'Developer', 'name': {'last': 'LastName', 'first': 'FirstName'}}
>>> my_dict.bob.job
'Developer'
>>> my_dict.bob.name
{'last': 'LastName', 'first': 'FirstName'}
It does require some overhead, as you will need to build your dicts based on MyDict. Regular dicts won't work if added to this dict.
This supports setting a new value as well:
>>> my_dict.bob.job = 'QA'
>>> my_dict.bob.job
'QA'
If you want to update Bob's job you can access it using my_dict['bob']['job']
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
my_dict['bob']['job'] = 'QA'
print(my_dict)
>> {'bob': {'name': {'last': 'LastName', 'first': 'FirstName'}, 'job': 'QA'}}
or by splitting your string:
my_dict = {
'bob': {
'name': {'first': 'FirstName', 'last': 'LastName'},
'job': 'Developer'
}
}
bobjob_key_value = 'bob.job=QA'
key, value = bobjob_key_value.split('=')
key = key.split('.')
my_dict[key[0]][key[1]] = value
print(my_dict)
>> {'bob': {'job': 'QA', 'name': {'last': 'LastName', 'first': 'FirstName'}}}
import yaml
def get_dictionary_replace_value(file, new_value, strip_qoutes=True):
with open(file, 'r') as rf:
yaml_doc = yaml.load(rf)
rf.close()
key, value = new_value.split('=')
keys = key.split('.')
inner_dict = yaml_doc
for i in keys[:-1]:
inner_dict = inner_dict[i]
inner_dict[keys[-1]] = value
with open(file, 'w') as wf:
if strip_qoutes:
wf.write(yaml.dump(yaml_doc,
default_flow_style=False).replace("'", "").replace('"', ""))
else:
wf.write(yaml.dump(yaml_doc, default_flow_style=False))
wf.close()

Python dictionary isn't updating

def mergeDict(object):
dict1 = {}
for i in range(len(object)):
dict1.update({'id': object[i].id, 'name': object[i].name, 'age': object[i].age, 'location': object[i].location})
return dict1
merged_dict = mergeDict(details_sorted)
But this doesn't work.
I want to get something like this:
{1: {'id': 1, 'name': 'John', 'age': '25'; 'location': 'somewhere'},
2: {'id': 2, 'name': ......}}
It looks like the return statement is in the for loop, which means it will only ever return the update of the first dict.
You don't want to update the dict; you just want to insert a value on key i. Also, the return goes after the for, not in it. Here is a modified version:
def mergeDict(object):
dict1 = {}
for i in range(len(object)):
dict1[i] = {'id': object[i].id, 'name': object[i].name, 'age': object[i].age, 'location': object[i].location}
return dict1
merged_dict = mergeDict(details_sorted)
Your update version would have updated the id, name, age and location keys of dict1 -- and you don't want that. You want to update the id key of dict1 with another dictionary containing the keys id, name, age and location.
Do a bit of experiment.
def mergeDict(object):
dict1 = {}
dict1.update({'id': 'object[i].id', 'name': 'object[i].name', 'age': 'object[i].age', 'location': 'object[i].location'})
dict1.update({'id': 'object[j].id', 'name': 'object[j].name', 'age': 'object[j].age', 'location': 'object[j].location'})
return dict1
merged_dict = mergeDict(None)
print merged_dict
Output:
{'name': 'object[j].name', 'age': 'object[j].age', 'location': 'object[j].location', 'id': 'object[j].id'}
Errors:
Only last object values are retained as the keys are same for all objects. So the for loop has no effect.
It's like saying
x = {}
x['k'] = y
x['k'] = z
There is only one key - k and it's latest value is z
One-liner in Python 3.0:
merged_dict = {i: dict(id=o.id, name=o.name, age=o.age, location=o.location)
for i, o in enumerate(details_sorted)}
If the result keys are consecutive integers, why not a list instead of dict?
merged = [ dict(id=o.id, name=o.name, age=o.age, location=o.location)
for i, o in enumerate(details_sorted) ]
A list has the added benefit of preserving sort order.

Categories

Resources