Wrong output in appending items to a dictionary of dictionary in python - python

I have this empty dictionary of dictionary in python and I am trying to append/add items to it. The individual inner dictionary itself has list as its value for key.
The empty structure of my dict of dict is:
grp_task_text_dict = {'Group 1': {}, 'Group 2': {}}
Here is my current code which reads items and based on certain conditions, it needs to append that item to either Group 1 or Group 2:
def text_mapping_bot2():
group_list = ['Group 1','Group 2']
task_text_dict = {}
grp_task_text_dict = {i: task_text_dict for i in group_list}
grp_mapping = {i: [] for i in group_list}
print('EMPTY GROUP TASK TEXT DICT = {}'.format(grp_task_text_dict))
bot_mapping = [{'Name': '', 'Task ID': '0','Task Text': 'Try again!', 'Group': '', 'Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '1.0','Task Text': 'Hi, Welcome', 'Group': 'Group 2', 'Complementary Action': 'group'}, {'Name': 'Hello', 'Task ID': '11.0', 'Task Text': 'Tell me about car options? ', 'Group': 'Group 2', 'Complementary Action': ''}, {'Bot Name': 'Hello', 'Task ID': '11.0', 'Task Text': 'What are different car options?', 'Group': 'Group 2', 'Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '11.0','Task Text': 'What cars are there?', 'Group': 'Group 2','Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '11.0','Task Text': 'May I know about Car types?', 'Group': 'Group 2','Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '2.0', 'Task Text': 'How much is the rent of compact car? ', 'Group': 'Group 2','Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '2.0','Task Text': 'Compact car expenses?', 'Group': 'Group 2', 'Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '2.0', 'Task Text': 'Cost of compact car?', 'Group': 'Group 2', 'Complementary Action': ''}, {'Name': 'Hello', 'Task ID': '2.0','Task Text': 'How much do I need to pay for small car', 'Group': 'Group 2', 'Complementary Action': ''}]
for item in bot_mapping:
print("ITEM IN BOT MAPPING = {}".format(item))
print('\n')
print('\n')
for grp, val in grp_task_text_dict.items():
print('CURRENT VAL = {} and GROUP = {}'.format(val, grp))
try:
if last_id < int(float(item['Task ID'])):
last_id = int(float(item['Task ID']))
except:
pass
try:
if item['Task ID'] == '':
item['Task ID'] = '0'
if (item['Task ID'] in val) and (str(item['Group']).lower() == str(grp).lower()):
print('\n')
print('CURRENT STATUS OF GROUP TASK TEXT DICT BEFORE APPENDING= {}'.format(
grp_task_text_dict))
print('\n')
print('GROUP AND TASK ID ALREADY IN ITEM AND TASK TEXT DICT IS SAME - {} and {}'.format(
str(item['Group']).lower(), str(grp).lower()))
print('\n')
print('APPENDING TO THIS GROUP IN GRP TASK DICT = {}'.format(grp_task_text_dict[grp][item['Task ID']]))
# val[item['Task ID']].append(item['Task Text'])
grp_task_text_dict[grp][item['Task ID']].append(item['Task Text'])
print('CURRENT STATUS OF GROUP TASK TEXT DICT AFTER APPENDING= {}. Going to Break out of loop'.format(
grp_task_text_dict))
break
elif str(item['Group']).lower() == str(grp).lower():
print('CURRENT STATUS OF GROUP TASK TEXT DICT BEFORE APPENDING IN NEW TASK ID= {}'.format(
grp_task_text_dict))
print('\n')
print('NEW TASK ID BUT GROUP SAME = {} and {}'.format(str(item['Group']).lower(), str(grp).lower()))
print('\n')
print('APPENDING TO THIS GROUP IN GRP TASK DICT IN NEW ID = {}'.format(grp_task_text_dict[grp]))
print('\n')
# val[item['Task ID']] = [item['Task Text']]
grp_task_text_dict[grp][item['Task ID']] = [item['Task Text']]
print(
'CURRENT STATUS OF GROUP TASK TEXT DICT AFTER APPENDING IN NEW TASK ID = {}. Going to Break out of loop'.format(
grp_task_text_dict))
break
except Exception as e:
print("THIS EXCEPTION CAME = {}".format(e))
# print('--iteration check--', task_text_dict)
What I want is that based on Group filed in each item in bot_mapping, the code should either append it to the list associated with Task ID of that group dictionary in grp_task_text_dict if the Task ID is already existing in that group dictionary, or create a new list with new Task ID within the matching group dictionary in grp_task_text_dict. So for example if Group in item is Group 2 and Task ID is 11.0 then this item should be appended to list of Task ID 11.0 in Group 2 dictionary of grp_task_text_dict and not in Group 1.
When I execute this code it appends the item to both Group 1 and Group 2 dictionaries even though my code is appending to specific group using grp_task_text_dict[grp][item['Task ID']].append(item['Task Text']) after matching the Group name using if (item['Task ID'] in val) and (str(item['Group']).lower() == str(grp).lower()):.
A sample output of my code looks like this:
ITEM IN BOT MAPPING = {'Bot Name': 'Hello', 'Task ID': '11.0', 'Task Text': 'What are different car options?', 'Group': 'Group 2', 'Complementary Action': ''}
CURRENT VAL = {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ']} and GROUP = Group 1
CURRENT VAL = {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ']} and GROUP = Group 2
CURRENT STATUS OF GROUP TASK TEXT DICT BEFORE APPENDING= {'Group 1': {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ']}, 'Group 2': {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ']}}
GROUP AND TASK ID ALREADY IN ITEM AND TASK TEXT DICT IS SAME - group 2 and group 2
APPENDING TO THIS GROUP IN GRP TASK DICT = ['Tell me about car options? ']
CURRENT STATUS OF GROUP TASK TEXT DICT AFTER APPENDING= {'Group 1': {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ', 'What are different car options?']}, 'Group 2': {'1.0': ['Hi, Welcome'], '11.0': ['Tell me about car options? ', 'What are different car options?']}}
As you can see above it is appending to both Group 1 and Group 2 when it should only append to Group 2.
I know there is some error in my logic but I am unable to figure out what and where the issue is which is causing this wrong output. Any help?

The problem is this line:
grp_task_text_dict = {i: task_text_dict for i in group_list}
This makes all the elements in this dictionary refer to the same task_text_dict dictionary, they don't get copies. Change it to:
grp_task_text_dict = {i: {} for i in group_list}
Then it will initialize each dictionary element with its own empty dictionary.

Related

How to remove the duplicate dictionaries from the list of dictionaries where dictionary contains an another dictionary? [duplicate]

This question already has answers here:
Remove duplicate dict in list in Python
(16 answers)
Closed 8 months ago.
I have a bit complex list of dictionaries which looks like
[
{'Name': 'Something XYZ', 'Address': 'Random Address', 'Customer Number': '-', 'User Info': [{'Registration Number': '17002', 'First Name': 'John', 'Middle Name': '', 'Last Name': 'Denver'}, {'Registration Number': '27417', 'First Name': 'Robert', 'Middle Name': '', 'Last Name': 'Patson'}]},
{'Name': 'Something XYZ', 'Address': 'Random Address', 'Customer Number': '-', 'User Info': [{'Registration Number': '27417', 'First Name': 'Robert', 'Middle Name': '', 'Last Name': 'Patson'}, {'Registration Number': '17002', 'First Name': 'John', 'Middle Name': '', 'Last Name': 'Denver'}]}
]
Expected is below
[
{'Name': 'Something XYZ', 'Address': 'Random Address', 'Customer Number': '-', 'User Info': [{'Registration Number': '17002', 'First Name': 'John', 'Middle Name': '', 'Last Name': 'Denver'}, {'Registration Number': '27417', 'First Name': 'Robert', 'Middle Name': '', 'Last Name': 'Patson'}]},
]
I want to remove the duplicate dictionaries in this list but I don't know how to deal with User Info because the order of the items might be different. A duplicate case would be where all the dictionary items are exactly the same and in the case of User Info order doesn't matter.
I think the best way is to make a hash of User Info by sum the hash values of it's elements (sum will tolerate position change).
def deepHash(value):
if type(value) == list:
return sum([deepHash(x) for x in value])
if type(value) == dict:
return sum([deepHash(x) * deepHash(y) for x, y in value.items()])
return hash(str(value))
and you can simply check the hash of you inputs:
assert deepHash({"a": [1,2,3], "c": "d"}) == deepHash({"c": "d", "a": [3,2,1]})

Is there a way to extract the selected value in a nested Dictionary using a for loop?

Using this dictionary, is there a way I can only extract the Name, Last Name, and Age of the boys?
myDict = {'boy1': {'Name': 'JM', 'Last Name':'Delgado', 'Middle Name':'Goneza', 'Age':'21',
'Birthday':'8/22/2001', 'Gender':'Male'},
'boy2': {'Name': 'Ralph', 'Last Name':'Tubongbanua', 'Middle Name':'Castro',
'Age':'21', 'Birthday':'9/5/2001', 'Gender':'Male'},}
for required in myDict.values():
print (required ['Name', 'Last Name', 'Age'])
The output is:
JM
Ralph
What I have in mind is
JM Delgado 21
Ralph Tubongbanua 21
You have to extract the keys one by one:
myDict = {'boy1': {'Name': 'JM', 'Last Name':'Delgado', 'Middle Name':'Goneza', 'Age':'21',
'Birthday':'8/22/2001', 'Gender':'Male'},
'boy2': {'Name': 'Ralph', 'Last Name':'Tubongbanua', 'Middle Name':'Castro',
'Age':'21', 'Birthday':'9/5/2001', 'Gender':'Male'},}
for required in myDict.values():
print (required['Name'], required['Last Name'],required['Age'])
this could be a solution:
myDict = {'boy1': {'Name': 'JM', 'Last Name':'Delgado', 'Middle, Name':'Goneza', 'Age':'21', 'Birthday':'8/22/2001', 'Gender':'Male'},
'boy2': {'Name': 'Ralph', 'Last Name':'Tubongbanua', 'Middle Name':'Castro',
'Age':'21', 'Birthday':'9/5/2001', 'Gender':'Male'},}
for required in myDict.values():
print(required ['Name'], required['Last Name'], required['Age'])
When printing multiple values separated with commas, a space will automatically appear between them.

Assign values from list to dictionary without for loop in Python

I need the same output by not using any loops.
I have two lists:
groupVal = ["Staff 1","Staff 2"]
nameValue = ["ABC","XYZ"]
My code looks like this:
sdict = {"group": {}}
for index, item in enumerate(groupVal):
sdict ['group'][item] = {"name": "Hi "+nameValue[index], "approval" :"yes"}
Output for sdict:
{'group': {'Staff 1': {'name': 'Hi ABC', "approval" :"yes"}, 'Staff 2': {'name': 'Hi XYZ', "approval" :"yes"}}}
Even better, a one liner for the whole sdict
groupVal = ["Staff 1","Staff 2"]
nameValue = ["ABC","XYZ"]
sdict = {'group': {item: {'name': 'Hi ' + value, 'approval': 'yes'} for item, value in zip(groupVal, nameValue)}}
sdict
{'group': {
'Staff 1': {'name': 'Hi ABC', 'approval': 'yes'},
'Staff 2': {'name': 'Hi XYZ', 'approval': 'yes'}
}
}

Create a key in a nested dict without using update function

Input :
{'Name': 'A','Blood Group': 'O +ve', 'Age': '1', 'Sex': 'M','Phone Number': '01234567', 'Mobile Number': '9876543210', 'Date of Birth': '01-01-95'}
1.
d.update({'Contact Info': {'Mobile Number':d['Mobile Number'],'Phone
Number':d['Phone Number'] }})
2.
d['Contact Info']={}
d['Contact Info']['Mobile Number']=d['Mobile Number']
Can you say any better way or different way to create a dictionary key which can be assigned to a dict item as value???
Original Code:
import csv
import copy
from collections import namedtuple
d={}
ls=[]
def nest():
with open ("details.csv", 'r') as f:
reader=csv.DictReader(f)
for row in reader:
d.update(row)
PersonalDetails = namedtuple('PersonalDetails','blood_group age sex')
ContactInfo = namedtuple('ContactInfo','phone_number mobile_number')
d1=copy.deepcopy(d)
ls.append(d1)
print ls
nest()
This is how I would update my dict of dicts:
I would create a function that will take a 3 arguments(The key of the subdict, the subkey of said subdict and the value you want to change.) I assign to be updated and then update that value.
d = {
'Name': 'A',
'Personal Details': {'Blood Group': 'O +ve', 'Age': '1', 'Sex': 'M'},
'Contact Info': {'Phone Number': '01234567', 'Mobile Number': '9876543210'},
'Date of Birth': '01-01-95'
}
def updateInfo(toBeUpdated, subkey, ValueToUpdate):
if toBeUpdated in d:
tempdict = d[toBeUpdated]
tempdict[subkey] = ValueToUpdate
d[toBeUpdated] = tempdict
print (d)
else:
print ("No %s to update" % (toBeUpdated))
updateInfo('Contact Info','Mobile Number','999 999 9999')
the result I get from this:
{'Name': 'A', 'Personal Details': {'Blood Group': 'O +ve', 'Age': '1', 'Sex': 'M'}, 'Contact Info': {'Phone Number': '01234567', 'Mobile Number': '999 999 9999'}, 'Date of Birth': '01-01-95'}

Dictionaries within a list

suppose I have the following list of dictionaries:
database = [{'Job title': 'painter', 'Email address': 'xxx#yyy.com', 'Last name': 'Wright', 'First name': 'James', 'Company': 'Swift'},
{'Job title': 'plumber', 'Email address': 'xxx#yyy.com', 'Last name': 'Bright', 'First name': 'James', 'Company': 'ABD Plumbing'},
{'Job title': 'brick layer', 'Email address': 'xxx#yyy.com', 'Last name': 'Smith', 'First name': 'John', 'Company': 'Bricky brick'}]
I'm entering the following code so I can print information about a person given their first name (I will be changing this, to search for last name, company, job title etc, using a variable):
print(next(item for item in database if item['First name'] == 'James'))
The issue arises as I have two First name's which are equal, namely James. How do I adjust the code so that it prints out information about all the James's in the database?
Remove the next().
print([item for item in database if item['First name'] == 'James'])

Categories

Resources