Return value from nested dictionary in Python - python

I'm trying to get values from a nested dict via user input. The problem is that the nested dictionaries have generic names (d1,d1, etc.). The user inputs, say, last name and the program returns the email.
I know this is basic, so I apologize in advance. This is what I have so far.
my_dict = {
'd1':{
'fname':'john',
'lname':'doe',
'age':'26',
'email':'jdoe#mail.com'
},
'd2':{
'fname':'mary',
'lname':'jane',
'age':'32',
'email':'mjane#mail.com'
}
}
lname = input("enter last name: ")
for emp in my_dict.items():
print(emp)
Output:
enter last name: john
('d1', {'fname': 'john', 'lname': 'doe', 'age': '26', 'email': 'jdoe#mail.com'})
('d2', {'fname': 'mary', 'lname': 'jane', 'age': '32', 'email': 'mjane#mail.com'})

This is a function that takes a last name as input, then iterates over each dictionary (key, value) pair and returns the email as soon as there is a match:
def get_email_from_last_name(last_name):
for v in my_dict.values():
if v['lname'] == last_name:
return v['email']
lname = input("enter last name: ")
email = get_email_from_last_name(lname)
print(email)
prints:
enter last name: doe
jdoe#mail.com

Per OP's comment, here is a solution with a simple tuple instead:
my_data = (
{
'fname':'john',
'lname':'doe',
'age':'26',
'email':'jdoe#mail.com'
},
{
'fname':'mary',
'lname':'jane',
'age':'32',
'email':'mjane#mail.com'
}
)
lname = input("enter last name: ")
for person in my_data:
if lname == person["lname"]:
print(person)
You can also map according to the last name, but that is not necessarily a one-to-one relationship.

Related

Removing a key from a dictionary using the value

Can I somehow delete a value from a dictionary using its key?
The function del_contact is supposed to delete a contact using only the name of the contact, but unfortunately I have the dictionary and the value, but not the key. How can this be solved?
my_contacts = {
1: {
"Name": "Tom Jones",
"Number": "911",
"Birthday": "22.10.1995",
"Address": "212 street"
},
2: {
"Name": "Bob Marley",
"Number": "0800838383",
"Birthday": "22.10.1991",
"Address": "31 street"
}
}
def add_contact():
user_input = int(input("please enter how many contacts you wanna add: "))
index = len(my_contacts) + 1
for _ in range(user_input):
details = {}
name = input("Enter the name: ")
number = input("Enter the number: ")
birthday = input("Enter the birthday")
address = input("Enter the address")
details["Name"] = name
details["Number"] = number
details["Birthday"] = birthday
details["Address"] = address
my_contacts[index] = details
index += 1
print(my_contacts)
def del_contact():
user_input = input("Please enter the name of the contact you want to delete: ")
my_contacts.pop(user_input)
add_contact()
print(my_contacts)
The problem is that my key of the dictionary is 1 or Name, and I want to be able to remove the contact using only the value of Name.
Basically what you can do is iterate of the dict and save only the keys without that user's name.
This code will do the trick:
my_contacts = {1: {"Name": "Tom Jones",
"Number": "911",
"Birthday": "22.10.1995",
"Address": "212 street"},
2: {"Name": "Bob Marley",
"Number": "0800838383",
"Birthday": "22.10.1991",
"Address": "31 street"}
}
user_input = "Tom Jones"
my_contacts = {key: value for key, value in my_contacts.items() if value["Name"] != user_input}
There's two steps here:
Finding the key/value pair(s) that match
Deleting the keys you found
If you're only deleting a single item (even with multiple matches), always, these can be combined:
def del_contact():
user_input = input("Please enter the name of the contact you want to delete: ")
for k, v in my_contacts.items(): # Need both key and value, we test key, delete by value
if v["Name"] == user_input:
del my_contacts[k]
break # Deleted one item, stop now (we'd RuntimeError if iteration continued)
else:
# Optionally raise exception or print error indicating name wasn't found
If you might delete multiple entries, and must operate in place, you'd split the steps (because it's illegal to continue iterating a dict while mutating the set of keys):
def del_contact():
user_input = input("Please enter the name of the contact you want to delete: ")
to_delete = [k for k, v in my_contacts.items() if v["Name"] == user_input]
if not to_delete:
# Optionally raise exception or print error indicating name wasn't found
for k in to_delete:
del my_contacts[k]
Or if you're okay with replacing the original dict, rather than mutating it in place, you can one-line the multi-deletion case as:
def del_contact():
global my_contacts # Assignment requires explicitly declared use of global
user_input = input("Please enter the name of the contact you want to delete: ")
my_contacts = {k: v for k, v in my_contacts.items() if v["Name"] != user_input} # Flip test, build new dict
# Detecting no matches is more annoying here (it's basically comparing
# length before and after), so I'm omitting it
I think thats what you need, hope that helps:
Code:
my_contacts = {1: {"Name": "Tom Jones",
"Number": "911",
"Birthday": "22.10.1995",
"Address": "212 street"},
2: {"Name": "Bob Marley",
"Number": "0800838383",
"Birthday": "22.10.1991",
"Address": "31 street"}
}
def add_contact():
user_input = int(input("please enter how many contacts you wanna add: "))
index = len(my_contacts) + 1
for _ in range(user_input):
details = {}
name = input("Enter the name: ")
number = input("Enter the number: ")
birthday = input("Enter the birthday")
address = input("Enter the address")
details["Name"] = name
details["Number"] = number
details["Birthday"] = birthday
details["Address"] = address
my_contacts[index] = details
index += 1
print(my_contacts)
add_contact()
print(my_contacts)
def del_contact():
user_input = input("Please enter the name of the contact you want to delete: ")
values = [key for key in my_contacts.keys() if user_input in my_contacts[key].values()]
for value in values:
my_contacts.pop(value)
del_contact()
print(my_contacts)
Input:
{1: {'Name': 'Tom Jones', 'Number': '911', 'Birthday': '22.10.1995', 'Address': '212 street'}, 2: {'Name': 'Bob Marley', 'Number': '0800838383', 'Birthday': '22.10.1991', 'Address': '31 street'}, 3: {'Name': 'myname', 'Number': '1233455', 'Birthday': '12-12-22', 'Address': 'blabla street'}}
Please enter the name of the contact you want to delete: Bob Marley
Output:
{1: {'Name': 'Tom Jones', 'Number': '911', 'Birthday': '22.10.1995', 'Address': '212 street'}, 3: {'Name': 'myname', 'Number': '1233455', 'Birthday': '12-12-22', 'Address': 'blabla street'}}
Being that the index are used as keys for the dictionary, the range function can be used as follows:
def del_contact():
user_input = input("Please enter the name of the contact you want to delete: ")
for i in range(1,len(my_contacts)+1):
if my_contacts[i]['Name'] == user_input:
del my_contacts[i]
break
If there can be multiple contacts with the same name that need to be deleted, remove the break statement.
But as mentioned in the comments, there is no need to use an index as a key for the dictionaries. A potential bug you'll encounter with that, is if the first entry is deleted whose name is Tom Jones the dict will have a length of 1 with only one key - 2. Then when you try to add more contacts, when you check the length of the dictionary index = len(my_contacts) + 1, since length is 1, index will be 2. Hence my_contacts[index] = details will update the contact with a key of 2 or "Name": "Bob Marley" instead of adding a new contact.

Mongodb adding a new field in an existing document, with specific position

I am facing this issue where I need to insert a new field in an existing document at a specific position.
Sample document: {
"name": "user",
"age" : "21",
"designation": "Developer"
}
So the above one is the sample document,what I want is to add "university" : "ASU" under key "age" is this possible?
Here's what you can do, first take the document as a dict, then we will determine the index of age and then we will do some indexing, look below:
>>> dic = { "name": "user", "age" : "21", "designation": "Developer" }
>>> dic['university'] = 'ASU'
>>> dic
{'name': 'user', 'age': '21', 'designation': 'Developer', 'university': 'ASU'}
Added the university field, now we will do some exchanging by using dic.items().
>>> i = list(dic.items())
>>> i
[('name', 'user'), ('age', '21'), ('designation', 'Developer'), ('university', 'ASU')]
#now we will acquire index of 'age' field
>>> index = [j for j in range(len(i)) if 'age' in i[j]][0]
#it will return list of single val from which we will index the val for simplicity using [0]
>>> index
1
#insert the last element ('university') below the age field, so we need to increment the index
>>> i.insert(index+1,i[-1])
# then we will create dictionary by removing the last element which is already inserted below age
>>> dict(i[:-1])
{'name': 'user', 'age': '21', 'university': 'ASU', 'designation': 'Developer'}

Duplicates string in dictionary of json file cannot be parsed onto pair of key/value

I have problem to parse some of string associate with the 'details' key.
the value of details key have duplicates string that should be extract as a pair of key/value.
This is sample of json data
{
"response": {
"client_log": {
"data": [
{
"login": "AAAAAAAAAAAAAA",
"state": "MC",
"details": "Please find report below:\r\n\r\n------Report Information------\r\n\r\nEmail Id: user1#gmail.com\r\nServ Id: 112233\r\nProd Num: 11111\r\nProd Unit: Super-A\r\nProd Type: type-A\r\n,Serv Id: 445566\r\nProd Num: 22222\r\nProd Unit: Super-C\r\nProd Type: type-A\r\n,Serv Id: 003377\r\nProd Num: 123456\r\nProd Unit: Super-B\r\nProd Type: type-X\r\nState: LONDON\r\nCity: LONDON\r\n\r\n------Service Information------\r\n\r\nUser Name: John Clark\r\nMobile Number: 000111222\r\n\r\n------Reported Form------\r\n\r\nForm-1: zzzzz\r\nType: 111\r\n\r\nRemarks: Remarks 123.",
"log_number": "1"
},
{
"login": "BBBBBBBBBBBBB",
"state": "XX",
"details": "Please find report below:\r\n\r\n------Report Information------\r\n\r\nEmail Id: user2#gmail.com\r\nServ Id: 767878\r\nProd Num: 34689\r\nProd Unit: Super-B\r\nProd Type: type-B\r\n,Serv Id: 128900\r\nProd Num: 13689\r\nProd Unit: Super-A\r\nProd Type: type-B\r\n,Serv Id: 96333\r\nProd Num: 0011321\r\nProd Unit: Super-C\r\nProd Type: type-C\r\nState: State2\r\nCity: City2\r\n\r\n------Service Information------\r\n\r\nUser Name: Marry\r\nMobile Number: 982130989\r\n\r\n------Reported Form------\r\n\r\nForm-1: xxxxxx\r\nType: 222\r\n\r\nRemarks: Remarks 456.",
"log_number": "1"
}
],
"query": "13"
},
"response_time": "0.723494",
"transaction_id": "909122",
"transaction_status": "OK"
}
}
from sample above please refer to details key below
"details": "Please find report below:\r\n\r\n------Report Information------\r\n\r\nEmail Id: user1#gmail.com\r\nServ Id: 112233\r\nProd Num: 11111\r\nProd Unit: Super-A\r\nProd Type: type-A\r\n,Serv Id: 445566\r\nProd Num: 22222\r\nProd Unit: Super-C\r\nProd Type: type-A\r\n,Serv Id: 003377\r\nProd Num: 123456\r\nProd Unit: Super-B\r\nProd Type: type-X\r\nState: LONDON\r\nCity: LONDON\r\n\r\n------Service Information------\r\n\r\nUser Name: John Clark\r\nMobile Number: 000111222\r\n\r\n------Reported Form------\r\n\r\nForm-1: zzzzz\r\nType: 111\r\n\r\nRemarks: Remarks 123.",
got duplicates keys for example keys 'Prod Num', Prod Unit' and Prod Type' in the example above the keys appeared twice.
When I read the file it did not return all the key require under 'details'...the sample output as follows
{
'city': 'LONDON',
'login': 'AAAAAAAAAAAAAA',
'state': 'MC',
'details': 'Please find report below:\r\n\r\n------Report Information------\r\n\r\nEmail Id: user1#gmail.com\r\n**Serv Id: 112233\r\nProd Num: 11111\r\nProd Unit: Super-A\r\nProd Type: type-A\r\n,Serv Id: 445566\r\nProd Num: 22222\r\nProd Unit: Super-C\r\nProd Type: type-A\r\n,Serv Id: 003377\r\nProd Num: 123456\r\nProd Unit: Super-B\r\nProd Type: type-X**\r\nState: LONDON\r\nCity: LONDON\r\n\r\n------Service Information------\r\n\r\nUser Name: John Clark\r\nMobile Number: 000111222\r\n\r\n------Reported Form------\r\n\r\nForm-1: zzzzz\r\nType: 111\r\n\r\nRemarks: Remarks 123.',
'log_number': '1',
'department': 'Sales',
'staff_id': 'S123',
'staff_name': 'EricY',
'timestamp': '2020-02-27 15:57:24',
'Email_Id': 'user1#gmail.com',
'Serv_Id': '112233',
'Prod_Num': '123456',
'Prod_Unit': 'Super-B',
'Prod_Type': 'type-X',
',Serv_Id': '003377',
'State': 'LONDON',
'City': 'LONDON',
'User_Name': 'John Clark',
'Mobile_Number': '000111222',
'Form-1': 'zzzzz',
'Type': '111',
'Remarks': 'Remarks 123.'
},
If you can see from above output I got
'Serv_Id': '112233' , 'Prod_Num': '123456', 'Prod_Unit': 'Super-B', 'Prod_Type': 'type-X' and ',Serv_Id': '003377'
because of the same keys it will replaced the values of each keys with the last/latest values ... in this case as per below values...the earlier values is replaced.
Prod Num: 123456, Prod Unit: Super-B and Prod Type: type-X after key ',Serv_Id': '003377'
I think it is due of duplicates keys. Some dictionary also got more than one ',Serv_Id' key... and this would mean more duplicates Prod Num, Prod Unit and Prod Type in the dictionary list and cannot be read properly as a key pair. The same keys will be replaced with the latest values...
How to overcome this duplicates key? maybe to change the key name to different name to make it unique.
I expect the output something as below
{
'city': 'LONDON',
'login': 'AAAAAAAAAAAAAA',
'state': 'MC',
'details': 'Please find report below:\r\n\r\n------Report Information------\r\n\r\nEmail Id: user1#gmail.com\r\nServ Id: 112233\r\nProd Num: 11111\r\nProd Unit: Super-A\r\nProd Type: type-A\r\n,Serv Id: 445566\r\nProd Num: 22222\r\nProd Unit: Super-C\r\nProd Type: type-A\r\n,Serv Id: 003377\r\nProd Num: 123456\r\nProd Unit: Super-B\r\nProd Type: type-X\r\nState: LONDON\r\nCity: LONDON\r\n\r\n------Service Information------\r\n\r\nUser Name: John Clark\r\nMobile Number: 000111222\r\n\r\n------Reported Form------\r\n\r\nForm-1: zzzzz\r\nType: 111\r\n\r\nRemarks: Remarks 123.',
'log_number': '1',
'department': 'Sales',
'staff_id': 'S123',
'staff_name': 'EricY',
'timestamp': '2020-02-27 15:57:24',
'Email_Id': 'user1#gmail.com',
'Serv_Id': '112233', ------>1st Serv_Id
'Prod_Num_1': '111111',--->1st prod_num with new keyname
'Prod_Unit_1': 'Super-A', --->1st prod_unit with new keyname
'Prod_Type_1': 'type-A', --->1st prod_type with new keyname
',Serv_Id': '003377',------>2nd Serv_Id with new keyname
'Prod_Num_2': '123456',--->2nd prod_num with new keyname
'Prod_Unit_2': 'Super-B', --->2nd prod_unit with new keyname
'Prod_Type_2: 'type-X', ---> 2nd prod_type with new keyname
'State': 'LONDON',
'City': 'LONDON',
'User_Name': 'John Clark',
'Mobile_Number': '000111222',
'Form-1': 'zzzzz',
'Type': '111',
'Remarks': 'Remarks 123.'
},
***The ',Serv_Id' key can be more than one. ***
Below is the script i used to read the file and extract 'details' to a keypair.
for entry in mydata['response']['client_log']['data']:
parsed_details = {}
for line in entry['details'].split('\r\n'):
try:
key, value = line.split(': ', maxsplit=1)
parsed_details[key] = value
parsed_details = { x.translate({32:'_'}) : y
for x, y in parsed_details.items()}
except ValueError:
pass
entry.update(parsed_details)
I appreciate your help on this matter. Please guide me. Thank you
Edit: I wrote this up pretty late last night, and came back to make a few edits.
In this case, you can use some simple string manipulation to do what you are hoping to do. I made some edits to your original code and have highlighted the differences in the comments of the code.
import json
myfile = 'sample.json'
with open(myfile, 'r') as f:
mydata = json.load(f)
for entry in mydata['response']['client_log']['data']:
my_keys = []
my_values = []
for i, line in enumerate(entry['details'].split('\r\n')):
# If we find ": " in the line, then it contains a key, value pair
if ": " in line:
# Strip the line of whitespace and "," and then split it on ":"
line = line.strip().strip(",").split(":")
# Add the key to the keys array, and add the value to the values
my_keys.append(line[0].replace(" ", "_"))
my_values.append(line[1].strip())
# Set an increment variable
inc = 1
parsed_details = {}
key_str = ""
# For each key and value in the keys and values
for key, value in zip(my_keys, my_values):
# If their are duplicate keys of the given key
if my_keys.count(key) > 1:
# Create a key_str to add onto the key
key_str = "_{}".format(inc)
key = key + key_str
# If this key exists, increment the counter by 1
if key in list(parsed_details.keys()):
inc += 1
# Strip the old key_str and add the new one
key = key.strip(key_str)+ "_{}".format(inc)
parsed_details[key] = value
entry.update(parsed_details)
print(mydata)

Verify the date of birth taken as user input with the value stored in nested dictionary in a list in python

I am trying to verify date of birth taken from user and comparing it with the value stored in dictionary database. But it is not verifying the value even if I have entered the right value of date of birth. Here is my code:
from collections import defaultdict
accountDetails = [
{"FirtsName": "JOHN", "LastName": "DENIS","date of Birth": "01-06-1992", "Account Number": "432524352345234", "Account Balance": "50000"},
{"FirtsName": "AKASH", "LastName": "MAHAJAN", "date of Birth": "04-02-1995","Account Number": "432524352345234", "Account Balance": "50000"},
{"FirtsName": "AMAN", "LastName": "RANA","date of Birth": "11-04-1996", "Account Number": "432524352345234", "Account Balance": "50000"},
{"FirtsName": "ANKUR", "LastName": "JAIN","date of Birth": "21-05-1990", "Account Number": "432524352345234", "Account Balance": "50000"},
]
d = defaultdict(lambda: defaultdict(dict))
for item in accountDetails:
d[item['FirtsName']][item['LastName']][item['date of Birth']] = item
# get valid first name
while True:
first_name_input = input('Enter First Name:\n').upper()
if first_name_input in d:
break
else:
print('Enter valid First Name')
# get valid last name
while True:
last_name_input = input('Enter Last Name:\n').upper()
if last_name_input in d[first_name_input]:
break
else:
print('Enter valid Last Name')
# get valid last name
while True:
dob_input = input('Enter dob:\n')
if dob_input in d[first_name_input]:
break
else:
print('Enter valid dob')
print(d[first_name_input][last_name_input])
The user has put the value as-04-02-1995
You need to test versus keys in the second level of your nested dictionary:
while True:
dob_input = input('Enter dob:\n')
if dob_input in d[first_name_input][last_name_input]:
break
else:
print('Enter valid dob')
This becomes clear when you print the structure of the nested dictionary you have created:
print(d)
defaultdict(<function __main__.<lambda>>,
{'AKASH': defaultdict(dict,
{'MAHAJAN': {'04-02-1995': {'Account Balance': '50000',
'Account Number': '432524352345234',
'FirtsName': 'AKASH',
'LastName': 'MAHAJAN',
'date of Birth': '04-02-1995'}}}),
...
'JOHN': defaultdict(dict,
{'DENIS': {'01-06-1992': {'Account Balance': '50000',
'Account Number': '432524352345234',
'FirtsName': 'JOHN',
'LastName': 'DENIS',
'date of Birth': '01-06-1992'}}})})

Tree style dictionary

I am stuck with the following data.
There is a list.
[{name: '/', children: [{name: 'bin'}, {name: 'sbin'}, {name: 'home'}]},
{name: 'home', children: [{name: 'user1'}, {name: 'user2'}]},
{name: 'user2', children: [{name: 'desktop'}]}]
I want to convert above list to the following dictionary.
{name: '/', children: [{name: '/bin'}, {name: '/sbin'}, {name: '/home', children: [{name: 'user1'}, {name: 'user2', children: [{name: 'desktop'}]}]}]}
I write some codes to convert data above style.
def recT(data, child, parent, collector):
dparent = dict(name=parent)
dchildren = dict()
lst = []
for c in child:
lst.append(dict(name=c['name']))
for d in data:
if c['name'] == d['name']:
if len(d) > 1:
dchildren.update(dict(children=recT(data, d['children'], d['name'], collector)))
dparent.update(dchildren)
collector.update(dparent)
return lst
Then,
myd = dict()
for d in data2:
if len(d) > 1:
recT(data2, d['children'], d['name'], myd)
NOTE: data2 is dictionary list I want to covert.
But, the output dictionary is the last record in list:
{'children': [{'name': 'desktop'}], 'name': 'user2'}
Please help.
As lazyr said, you can't duplicate keys in your dict like that. You could convert it to a format like the following to be valid python dict syntax:
{
'/': {
'bin': {},
'sbin': {},
'home': {
'user1': {},
'user2': {
'desktop': {}
}
}
}
The reason you're only getting the last record in the list is because your dict uses unique keys
mydict = {}
mydict['name'] = 1
mydict['name'] # is 1
mydict['name'] = 2
for x,y in mydict.iteritems():
print '{0}: {1}'.format(x,y)
>> name: 2 # Note only one entry
Now, I got it from #lazyr's answer of How to convert a strictly sorted list of strings into dict?.
Then, I converted into string and changed it into wanted format using myReplacer().
here:
def myReplacer(strdata):
strdata = strdata.replace("{", '{ name:')
strdata = strdata.replace(': {', ', children : [{')
strdata = strdata.replace('}', '}]')
strdata = strdata.replace(': None,', '},{ name:')
strdata = strdata.replace(': None', '')
strdata = strdata.replace(", '", "}, { name: '")
return strdata[:-1]
Thanks #lazyr and everybody helped me. It need some polish.

Categories