How can i merge several dictionaries by a for loop? - python

This is my code:
a = int(input())
for i in range(a):
b = input()
b = b.split(".")#creating a list
#print(b)
b[1]= b[1].lower()
b[1]=b[1].capitalize()
a=b[1]
#print(b[1])
#print(b[0] , b [1] , b[2])
dic = {}
dic_final={}
dic={b[1] : {'name':b[0] ,'lan':b[2] }}
dic_final.update(dic)
del(dic)
print(dic_final)
My input :
2
f.sara.python
m.john.java
Output has to be like :
{ 'sara':{'gender':'f' , 'lan':'python'} , 'john':{'gender':'m' , 'lan':'python'}}
But i always get the last dictionary item i wrote in the input :
{'john':{'gender':'m' , 'lan':'python'}
How can i solve it and get a dictionary like below?
{ 'sara':{'gender':'f' , 'lan':'python'} , 'john':{'gender':'m' , 'lan':'python'}}

this is a very clear solution that i came up with
num_sample = int(input("how many test cases?: "))
final = {}
for case in range(num_sample):
new_case = input("insert new case: ")
gender, name, lan = new_case.split(".")
info = {"gender": gender, "lan": lan}
final[name] = info
#access final from here

Create a global dictionary instead of creating a local one in the for loop. Moreover in your code, you are naming gender as name
a = int(input())
dic_final = {}
for i in range(a):
b = input()
b = b.split(".")
b[1]= b[1].lower()
b[1]=b[1].capitalize()
a=b[1]
dic={b[1] : {'gender':b[0] ,'lan':b[2] }}
dic_final.update(dic)
del(dic)
print(dic_final)
Output:
2
f.sara.python
m.john.java
{'Sara': {'gender': 'f', 'lan': 'python'}, 'John': {'gender': 'm', 'lan': 'java'}}

The reason you are getting only the last entry is because , you are re-initialising the dictionary for every iteration.
All you have to do is , make "dic_final" global .

You're overwriting the dic_final dictionary in the for loop each time.
This line is causing the issue dic_final={}
Solution:
Add this line before your 'for loop' and remove the declaration inside.
dic_final = dict()
Better coding style:
a = int(input())
dic_final = dict()
for i in range(a):
b = input()
gender, name, lan = b.split(".")
name = name.capitalize()
dic_final.update({name : {"gender": gender, "lan": lan}})
print(dic_final)
Output:
2
f.sara.python
m.john.java
{'Sara': {'gender': 'f', 'lan': 'python'}, 'John': {'gender': 'm', 'lan': 'java'}}

Related

Printing multiple list in a for loop

Hello I am trying to create the table below by using list. The product s and the prices are already in lists (priceList and productList). i have successfully created new more list where the person types in the product code and quantity (quan_inputed).
Any help would be greatly appreciated as I don't know what to do. I have tried several methods already and this is the closest I've come to getting multiple inputs at once.
Thank you
Try This:
def add_item():
code_inputed = []
quan_inputed = []
while True:
i = input("enter code: ")
if i != "END":
q = input("enter quantity: ")
code_inputed.append(int(i))
quan_inputed.append(int(q))
else:
break
return code_inputed,quan_inputed
def showRecord(code_inputed, quan_inputed):
product_info = {}
for kk in range(len(code_inputed)):
quan = quan_inputed[kk]
kk = code_inputed[kk]
price = priceList[kk]
product = productList[kk]
if kk not in product_info:
product_info[kk] = [kk, quan, price, product]
else:
product_info[kk][1] += quan
product_info[kk][2] = product_info[kk][1] * price
for x in ["Code", "Quanity", "Price", "Product"]:
print(x, end=" ")
print()
for x in product_info:
for info in product_info[x]:
print(info, end=" ")
print()
code_inputed, quan_inputed = add_item()
showRecord(code_inputed, quan_inputed)
Just to explain my comment about the other approach, I recommend storing the data in other way than just in multiple lists. For example like this:
items = [
{'code': 2, 'price': 39.95, 'quantity': 11, 'product': "Tea Set\t\t"},
{'code': 34, 'price': 19.95, 'quantity': 3, 'product': "Citrus Cather"}
]
print("Code\tProduct\t\t\tPrice $\tQuantinty\tCost $")
print("------------------------------------------------------")
for item in items:
print(f"{item.get('code')}\t\t{item.get('product')}\t{item.get('price')}\t{item.get('quantity')}\t\t\t{item.get('price') * item.get('quantity')}")
Those tabs (\t) in product name in dictionary are just to make the table nice, you should come up with nicer way to print it...
Result:

This Python code gives unwanted output when query_words if of size greater than 1

I've written some code, but it does not output what I expected.
Here is the code:
query_words = ['dollar', 'probabilistic']
query_word_to_synonym_dict = {'probabilistic': ['probabilistic'], 'dollar' : ['currency']}
mail_ids = {123, 108}
big_ds = {}
empty_dict = {}
index = {'probabilistic':{(108, 1)}, 'currency':{(123, 1)}}
for mail_id in mail_ids:
empty_dict = dict.fromkeys(query_words, [])
big_ds.update({mail_id:empty_dict})
for query_word in query_words:
syns = query_word_to_synonym_dict[query_word]
for syn in syns:
index_of_word = index[syn]
tuple_first = []
for tuples in index_of_word:
tuple_first.append(tuples[0])
for number in tuple_first:
(big_ds[number][query_word]).append(syn)
print(big_ds)
The expected final value of big_ds is:
{123: {'dollar': ['currency'], 'probabilistic': []}, 108: {'dollar': [], 'probabilistic': ['probabilistic']}}
But the code sets the value of big_ds to the following:
{123: {'dollar': ['currency'], 'probabilistic': ['currency']}, 108: {'dollar': ['probabilistic'], 'probabilistic': ['probabilistic']}}
I asked a similar question a while back: How do I resolve this unexpected output in Python code? and was able to solve the issue for that use case. But that code I wrote fails when query_words has a size>1.
I can't seem to figure out how to fix things. Any solution?
It's because:
dict.fromkeys(query_words, [])
...the keys in each mail_id sub-dict each share the same list instance.
See:
"Least Astonishment" and the Mutable Default Argument
Dictionary creation with fromkeys and mutable objects. A surprise
Try this instead:
query_words = ['dollar', 'probabilistic']
query_word_to_synonym_dict = {'probabilistic': ['probabilistic'], 'dollar' : ['currency']}
mail_ids = {123, 108}
big_ds = {}
index = {'probabilistic':{(108, 1)}, 'currency':{(123, 1)}}
for mail_id in mail_ids:
big_ds[mail_id] = {word: [] for word in query_words}
for query_word in query_words:
syns = query_word_to_synonym_dict[query_word]
for syn in syns:
index_of_word = index[syn]
tuple_first = []
for tuples in index_of_word:
tuple_first.append(tuples[0])
for number in tuple_first:
big_ds[number][query_word].append(syn)
print(big_ds)

Creating nested subdict python

I have some student names of different types and scores of each type in a list.
Eg:
students_exam_names = [exam_name1, exam_name2, exam_name3]
students_exam_score = [exam_score1, exam_score2, exam_score3]
students_quiz_names = [quiz_name1, quiz_name2]
students_quiz_score = [quiz_score1, quiz_score2]
students_homework_names = [homework_name1, homework_name2, homework_name3, homework_name4]
students_homework_score = [homework_score1, homework_score2, homework_score3, homework_score4]
Similarly for all three as shown below.
I want to have the details in the form of nested dict as follows:
details = {'students_exam':{
'exam_name1':exam_score1,
'exam_name2':exam_score2,
'exam_name3':exam_score3
},
'students_quiz':{
'quiz_name1': quiz_score1,
'quiz_name2': quiz_score2
},
'students_homework':{
'homework_name1': homework_score1,
'homework_name2': homework_score2,
'homework_name3': homework_score3,
'homework_name4': homework_score4,
}
The length of each students type is different. I tried to get it in the form of list of dictionaries as below but couldn't go further.
students_exam = {}
for i in range(len(students_exam_names)):
students_exam[students_exam_names[i]] = students_exam_score[i]
Do not forget to use ' when you are defining your inputs:
students_exam_names = ['exam_name1', 'exam_name2', 'exam_name3']
students_exam_score = ['exam_score1', 'exam_score2', 'exam_score3']
students_quiz_names = ['quiz_name1', 'quiz_name2']
students_quiz_score = ['quiz_score1', 'quiz_score2']
students_homework_names = ['homework_name1', 'homework_name2', 'homework_name3', 'homework_name4']
students_homework_score = ['homework_score1', 'homework_score2', 'homework_score3', 'homework_score4']
Then, simply use the zip function:
details = {'students_exam': dict(zip(students_exam_names, students_exam_score)),
'students_quiz': dict(zip(students_quiz_names, students_quiz_score)),
'students_homework': dict(zip(students_homework_names, students_homework_score))}
The output is:
{'students_exam': {'exam_name1': 'exam_score1', 'exam_name2': 'exam_score2', 'exam_name3': 'exam_score3'}, 'students_quiz': {'quiz_name1': 'quiz_score1', 'quiz_name2': 'quiz_score2'}, 'students_homework': {'homework_name1': 'homework_score1', 'homework_name2': 'homework_score2', 'homework_name3': 'homework_score3', 'homework_name4': 'homework_score4'}}
So what if i assume your complete set of inputs are like
students_exam_names = ['name1', 'name2', 'name3']
students_exam_score = ['score1', 'score2', 'score3']
students_quiz_names = ['name1', 'name2']
students_quiz_score = ['score1', 'score2']
students_homework_names = ['name1', 'name2', 'name3', 'name4']
students_homework_score = ['score1', 'score2', 'score3', 'score4']
if so then the following code should do the job.
details={}
details['students_exam']={sexam: students_exam_score[students_exam_names.index(sexam)] for sexam in students_exam_names}
details['students_quiz']={squiz: students_quiz_score[students_quiz_names.index(squiz)] for squiz in students_quiz_names}
details['students_homework']={shome: students_homework_score[students_homework_names.index(shome)] for shome in students_homework_names}
It looks like you need some functions to do these updates:
def update_exam(details, names, scores):
results = {}
for name,score in zip(names,scores):
results[name]=score
details['students_exam'] = results
def update_quiz(details, names, scores):
results = {}
for name,score in zip(names,scores):
results[name]=score
details['students_quiz'] = results
def update_homework(details, names, scores):
results = {}
for name,score in zip(names,scores):
results[name]=score
details['students_homework'] = results
details = {}
update_exam(details, students_exam_names, students_exam_score)
update_quiz(details, students_quiz_names, students_quiz_score)
update_homework(details, students_homework_names, students_homework_score)
But since the above functions only really differ in the text name of the key, they can be collapsed further:
def update(details, key, names, scores):
results = {}
for name,score in zip(names,scores):
results[name]=score
details[key] = results
details = {}
update(details,'students_exam', students_exam_names, students_exam_score)
update(details,'students_quiz', students_quiz_names, students_quiz_score)
update(details,'students_homework', students_homework_names, students_homework_score)
And then the loop can become a dictionary comprehension:
def update(details, key, names, scores):
details[key] = {name:score for (name,score) in zip(names,scores)}

Add gender column searching rows that contains info from 2 tables

I have a df that contains some emails:
Email
jonathat0420#email.com
12alexander#email.com
14abcdjoanna#email.com
maria44th#email.com
mikeasddf#email.com
I need to add a second column with the gender.
I will have 2 lists:
male_names = ['john', 'alex']
female_names = ['maria', joanna']
My output should look like that:
Email Gender
jonathat0420#email.com 1
12alexander#email.com 1
14abcdjoanna#email.com 2
maria44th#email.com 2
mikeasddf#email.com
I would need to search the emails that contains the names from the lists and if they are in the emails to add them a number, like "1" for males, 2 for "females" and leave empty for the emails without matching in the lists.
Can anybody help me with this?
You could simply use a map, like this:
def isinlist(email, names):
for name in names:
if name in email:
return True
return False
df.loc[:, 'Gender'] = df.Email.map(lambda x : 1 if isinlist(x, male_names) else (2 if isinlist(x, female_names) else None))
However, there are going to be a lot of ambiguous cases that risk being classified erroneously - e.g., "alexandra#email.com" would be classified as male, since alex is the list of male names.
Maybe you could implement a slighly more complex "best match" logic like this?
def maxmatchlen(email, names): # = length of longest name from list that is contained in the email
return max([len(name) for name in names if name in email] + [0]) # append a 0 to avoid empty lists
def f(email, male_names = male_names, female_names = female_names):
male_maxmatchlen = maxmatchlen(email, male_names)
female_maxmatchlen = maxmatchlen(email, female_names)
if male_maxmatchlen > female_maxmatchlen:
return 1
elif female_maxmatchlen > male_maxmatchlen:
return 2
else: # ambiguous case
return None
df.loc[:, 'Gender'] = df.Email.map(f)
It looks like you first must determine if the email contains a name. You can loop through both male and female. That will determine if the name is "in" the email. Then you could make a list or a dictionary of these.
#!/usr/bin/env python3
import os
def get_emails(filepath):
"""Open the data file and read the lines - return a list"""
with open(filepath, "r") as f:
email_list = f.readlines()
for email in email_list:
print(f'Email = {email}')
print(f'The total number of emails = {len(email_list)}')
return email_list
def find_names(email_list):
"""loop through the email list and see if each one contains a male or female name - return dictionary of tuples"""
male_names = ['john', 'alex', 'mike', 'jonathat']
female_names = ['maria', 'joanna']
name_dict = {}
for email in email_list:
for name_f in female_names:
if name_f in email:
data= (name_f , 1)
name_dict[email] = data
print(f"{email} is for {name_f} and is female {data[1]}")
continue
for name_m in male_names:
if name_m in email:
data= (name_m , 2)
name_dict[email] = data
print(f"{email} is for {name_m} and is male {data[1]}")
continue
return name_dict
if __name__ == '__main__':
your_Datafile = r"D:\Share\email.txt"
email_list = get_emails(your_Datafile)
my_dictionary = find_names(email_list)
print(my_dictionary)
for email, data in my_dictionary.items():
print(data[0], data[1], email)

For a dictionary compare both key and value with the values in a list

I have the following structures:
prev = { 'alpha:10.2': '145', 'teta:180': '198', 'eltira:140': '222', 'ronta:23.14':220}
now = ['alpha:10.3','teta:180', 'eltira:142']
and the following code:
old = []
for k, v in prev.iteritems():
if k not in now:
old.append(v)
So if the key from the dict prev is not found in the list now, I add the value to the old list.
Result 'old= [ '145', '222']`
But, I want to check also which part doesn't correspond from the key. I'm inclined to use namedtuple.
Package = collections.namedtuple('Package', 'name version')
for k, v in prev.items():
name, version = k.split(':')
Package(name=k, version='v')
if the name corresponds but the version not, do the same as above.
if the name is not found add it to a new list old_names, but also do as above.
The issue is that if k not in now will not work. I can do it with two loops and three ifs but maybe there is an option to do it more clean.
Expecting output:
old=[ '145', '222']
old_names=['ronta']
I have splitted the 'now' list and converted it to a dictionary (name:version) which takes a single iteration. Later, the values from the dictionary can be accessed in constant time for further operations.
prev = { 'alpha:10.2': '145', 'teta:180': '198', 'eltira:140': '222', 'old:1. 43':'150'}
now = ['alpha:10.3','teta:180', 'eltira:142']
now_dict = {}
old = []
old_names = []
for items in now:
temp0,temp1 = items.split(':')
now_dict[temp0] = temp1
for k,v in prev.items():
name,version = k.split(':')
if name not in now_dict.keys():
old_names.append(name)
old.append(v)
continue
if version != now_dict[name]:
old.append(v)
continue
else:
continue
if __name__ == '__main__':
print(old_names)
print(old)
Here is a way to do it:
prev = { 'alpha:10.2': '145', 'teta:180': '198', 'eltira:140': '222', 'zeta:12.1' : '334'}
now = ['alpha:10.3','teta:180', 'eltira:142']
now_splited = [nk.split(":") for nk in now]
old = []
old_name = []
for k, v in prev.items():
if k not in new_key:
old_n, old_v = k.split(":")
name = any(map(lambda n : n[0] == old_n, now_splited))
version = any(map(lambda n : n[1] == old_v, now_splited))
if name and not version:
old.append(v)
elif not name:
old_name.append(old_n
old.append(old_v))
Results :
>>> print(old, old_name)
['145', '222', '334'] ['zeta']
You can make now a dict by maping operator.methodcaller to it and wrapping it in dict() then a comprehension will be easy using the same method on prev:
splitter = operator.methodcaller('split', ':')
now_dict, kv_map = dict(map(splitter, now)), map(splitter, prev)
old = [prev[':'.join((k,v))] for k, v in kv_map if k in now_dict]
old_names = [n for n, v in kv_map if n not in now_dict]
Results:
#old
['145', '198', '222']
#old_names
[]

Categories