How can I connect two dictionaries in python? - python

I'm struggling a bit on a dictionary code in Python (mind I'm a new student without any earlier experience). The strings in this code is on Norwegian, hopefully that's not a problem. The code goes as follow
participants_and_allergens = {"Ole":["gluten", "egg"],
"Silje":["shellfish", "nuts"],
"Ragnar":["milk", "fish"]}
print(participants_and_allergens.keys())
allergens_and_foods = {"Garlic bread": ["gluten", "egg"],
"Fish soup": ["shellfish", "fish"],
"Chocolate Cake": ["milk", "egg"]}
def write_name():
name = input("What is your name?\n> ")#confirms the registration of the participant
if not participants_og_allergener.get(name):
print("Sorry,", name + " does not exist in the registry")
else:
print(name + " is registered and now confirmed")
print(allergens)
print(name + " has the allergens", allergens)
allergens = participants_og_allergener.get(name)
allergens_foods = allergens_and_foods.get("allergens")
print(allergens_foods)
write_name()
Essentially, what I'm asking is, is there any way to connect to dictionaries, which are independent? When the user enters a name, it should result in values linked to the name coming out, and elements from another dictionary.
I have realized I'll have to use a for loop, but I don't know how.
The expected output should be something like "Hi Ole, you have allergies to gluten and eggs and should stay away from the foods garlic bread and chocolate cake"

Related

How to create a search function of a list with multiple organized elements?

I'm trying to create a function with two inputs (number, people) whereas it searches from a list with multiple organized elements for the correct number and outputs the correct information (which the output is named: user).
Here's the list:
List = ([15209 Amanda Craig NC], [16428 Johnathan Smith OH], [12690 Samantha Owens IL], [17002 Mark Stenson NY], [13379 Francis Trent NC], [14904 Jake Peterson CA])
The number request (not a user-input):
14904
17002
19999
Desired output:
14904 Jake Peterson CA
17002 Mark Stenson NY
"User not found"
This is what I have at the moment. I'm not sure if I should use split, but then I have no clue what to do next.
people = ([15209 Amanda Craig NC], [16428 Johnathan Smith OH], [12690 Samantha Owens IL], [17002 Mark Stenson NY], [13379 Francis Trent NC], [14904 Jake Peterson CA])
user = people[i]
def search_user(number, people):
ID = people.split()[0]
if number != ID: #I'm not sure how I can find the numbers
return "User not found"
else:
return user
If anything is wrong, it is okay to scrap it. I'm a bit confused about where to even start.
If you're not married to the idea of having users in a Tuple containing lists, I suggest you work on making your data more easily available, to avoid looping over the user list.
Ideally, it would be a dictionary, where key would be the "id" and value the name of the person.
Working example:
from typing import Dict
users: Dict = {
15209: "Amanda Craig NC",
16428: "Johnathan Smith OH",
12690: "Samantha Owens IL",
}
def get_user_by_id(user_id: int) -> str:
return users.get(user_id, "Unknown User")
user: str = get_user_by_id(15209)
And if you insist on using a Tuple of lists, you should fix the syntax as was advised, which could lead for example to:
users = ([15209, "Amanda Craig NC"], [16428, "Johnathan Smith OH"], [12690, "Samantha Owens IL"], [17002, "Mark Stenson NY"], [13379, "Francis Trent NC"], [14904, "Jake Peterson CA"])
def search_user(number, users):
for user in users:
if user[0] == number:
return user
return "User not found"
print(search_user(14904, users))
print(search_user(17002, users))
print(search_user(19999, users))
That said, a dictionary would be far more relevant to your needs, as per the previous answer.
Assuming that the formatting of the list entries has, reliably, the ID in first position:
def search_user(number, users):
for user in users:
if number == int(users.split()[0]):
return user
return "User not found"

How can I send a routine email using a list as input?

I'm trying to write code in Python to help with sending an email that I send about twice a week, with the same format every time and just a few elements that differ between emails, so I wrote the following code to help with this:
def visitor():
visitors = []
number_of = int(input("How many visitors are you signing in? "))
time = input("What time are they coming? ")
comments = """
Please type the name of the first visitor, and their nationality on the next line, the name of the second visitor
and their nationality on the next line, until you wrote down all the names and nationalities.
If you wanna stop the program and execute the code with the names & nationalities, just type quit
"""
print(comments)
name, i = "", 1
while name != "quit":
name = str(input("Ignore: "))
visitors.append(name)
visitors = visitors.pop(-1)
email = f"""
Hello,
I have {number_of} visitors coming today at {time}.
Name: {visitors[i]}
Nationality: {visitors[i + 1]}
"""
for i in range(len(visitors)):
to_add = f"""
Name: {visitors[i]}
Nationality: {visitors[i + 1]}
"""
email += to_add
ending = "Awaiting your approval\nThank you"
email += ending
return email
visitor()
However, upon running this code, I run into a problem in line 25, saying "Index out of range" ( line 25 is Nationality: {visitors[i + 1]} ). This normally shouldn't happen since the list has more than one element. Can someone help with this?
P.S. I have another, way longer code written for this that works, but I wanted to try and improve it by making it less sloppy.
The visitors list is acceeded at offset i+1, and i go up to len(visitors)-1 (upper limit specified for the loop through range()), so there is an access out of range when i = len(visitors) - 1

Python - Replacing a specific value in a CSV file while keeping the rest

So I have a CSV file that looks something like this:
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
What I need to be able to do is let the user edit and change their Fav Artist and Fav Genre so that their new values are saved to the file in place of the old ones. I'm not the very advanced when it comes to CSV so I'm not sure where to begin with it, therefore any help and pointers will be greatly appreciated.
Thanks guys.
EDIT:
Adding the code I have so far so it doesn't seem like I'm just trying to get some easy way out of this, generally not sure what to do after this bit:
def editProfile():
username = globalUsername
file = open("users.csv", "r")
for line in file:
field = line.split(",")
storedUsername = field[0]
favArtist = field[4]
favGenre = field[5]
if username == storedUsername:
print("Your current favourite artist is:", favArtist,"\n" +
"Your current favourite genre is:",favGenre,"\n")
wantNewFavArtist = input("If you want to change your favourite artist type in Y, if not N: ")
wantNewFavGenre = input("If you want to change your favourite genre type in Y, if not N: ")
if wantNewFavArtist == "Y":
newFavArtist = input("Type in your new favourite artist: ")
if wantNewFavGenre == "Y":
newFavGenre = input("Type in your new favourite genre: ")
This is how it would look like using pandas
import pandas as pd
from io import StringIO
# Things you'll get from a user
globalUsername = "Den1994"
field = 'Fav Artist'
new_value = 'Linkin Park'
# Things you'll probably get from a data file
data = """
Username,Password,Name,DOB,Fav Artist,Fav Genre
Den1994,Denis1994,Denis,01/02/1994,Eminem,Pop
Joh1997,John1997,John,03/04/1997,Daft Punk,House
"""
# Load your data (e.g. from a CSV file)
df = pd.read_csv(StringIO(data)).set_index('Username')
print(df)
# Now change something
df.loc[globalUsername][field] = new_value
print(df)
Here df.loc[] allows you to access a row by the index. In this case Username is set as index. Then, [field] selects the column in that row.
Also, consider this:
df.loc[globalUsername][['Fav Artist', 'Fav Genre']] = 'Linkin Park', 'Nu Metal'
In case you have a my-data.csv file you can load it with:
df = pd.read_csv('my-data.csv')
The code above will return
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Eminem Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
and
Password Name DOB Fav Artist Fav Genre
Username
Den1994 Denis1994 Denis 01/02/1994 Linkin Park Pop
Joh1997 John1997 John 03/04/1997 Daft Punk House
Try this
import pandas as pd
data = pd.read_csv("old_file.csv")
data.loc[data.Username=='Den1994',['Fav Artist','Fav Genre']] = ['Beyonce','Hard rock']
data.to_csv('new_file.csv',index=False)
python has a built-in module dealing with csv, there are examples in the docs that will guide you right.
One way to do is to use the csv module to get the file you have into a list of lists, then you can edit the individual lists (rows) and just rewrite to disk what you have in memory.
Good luck.
PS: in the code that you have posted there is no assignment to the "csv in memory" based on the user-input
a minimal example without the file handling could be:
fake = 'abcdefghijkl'
csv = [list(fake[i:i+3]) for i in range(0, len(fake), 3)]
print(csv)
for row in csv:
if row[0] == 'd':
row[0] = 'changed'
print(csv)
the file handling is easy to get from the docs, and pandas dependance is avoided if that is on the wishlist

How to send scraped data through reddit bot

So I've got this bot that I want to use to reply with the box score of the mets game anytime someone says "mets score" on a specific subreddit. This is my first python project and I plan on using it on a dummy subreddit I created as a learning tool. I'm having trouble sending the scores from the website I scraped through the bot so it can appear in the reply to the "mets score" comments. Any suggestions?
import praw
import time
from lxml import html
import requests
from bs4 import BeautifulSoup
r = praw.Reddit(user_agent = 'my_first_bot')
r.login('user_name', 'password')
def scores():
soup = BeautifulSoup(requests.get("http://scores.nbcsports.com/mlb/scoreboard.asp?day=20160621&meta=true").content, "lxml")
table = soup.find("a",class_="teamName", text="NY Mets").find_previous("table")
a, b = [a.text for a in table.find_all("a",class_="teamName")]
inn, a_score, b_score = ([td.text for td in row.select("td.shsTotD")] for row in table.find_all("tr"))
print (" ".join(inn))
print ("{}: {}".format(a, " ".join(a_score)))
print ("{}: {}".format(b, " ".join(b_score)))
words_to_match = ['mets score']
cache = []
def run_bot():
print("Grabbing subreddit...")
subreddit = r.get_subreddit("random_subreddit")
print("Grabbing comments...")
comments = subreddit.get_comments(limit=40)
for comment in comments:
print(comment.id)
comment_text = comment.body.lower()
isMatch = any(string in comment_text for string in words_to_match)
if comment.id not in cache and isMatch:
print("match found!" + comment.id)
comment.reply('heres the score to last nights mets game...' scores())
print("reply successful")
cache.append(comment.id)
print("loop finished, goodnight")
while True:
run_bot()
time.sleep(120)
I think I'll just put you out of your misery ;). There are multiple issues with your code snippet:
comment.reply('heres the score to last nights mets game...' scores())
The .reply() method requires a string or an object that can have a good enough representation as a string. Assuming the method scores() returns a string, you should concatenate the two arguments, like this:
comment.reply('heres the score to last nights mets game...'+ scores())
It looks like your knowledge of basic python syntax and constructs is dusty. For a quick refresher see this.
Your method scores() doesn't return anything. It just prints out a bunch of lines (which I assume are for debugging purposes).
def scores():
soup = BeautifulSoup(requests.get("http://scores.nbcsports.com/mlb/scoreboard.asp?day=20160621&meta=true").content, "lxml")
.......
print (" ".join(inn))
print ("{}: {}".format(a, " ".join(a_score)))
print ("{}: {}".format(b, " ".join(b_score)))
Funnily enough you could use those exact strings for your return value (or maybe something else entirely, as suit your needs) like this:
def scores():
.......
inn_string = " ".join(inn)
a_string = "{}: {}".format(a, " ".join(a_score))
b_string = "{}: {}".format(b, " ".join(b_score))
return "\n".join([inn_string, a_string, b_string])
These should get you up and running.
More advice: Have you read the Reddit PRAW docs? You should. You should also probably use praw.helpers.comment_stream(). It's simple and easy to use and will handle retrieving new comments for you. Currently you try and fetch a maximum of 40 comments every 120 seconds. What happens when there are more than that many relevant comments in that 120 second span. You'll end up missing some of the comments you should've replied to. .comment_stream() will take care of rate limiting for you so that your bot can reply to each new comment which needs its attention at its own pace. Read more about this here.

Python: Problems when iterating over a dictionary

So, I have been working on this simple Python program to get familiar with dictionaries. Basically, it works as a database which you can search in. If your entry is in the dictionary key, it brings up the information regarding the entry.
Family = {'Jim' : ['cool guy', 'has facial hair'],
'Ned' : ['hot stuff', ' wears Tees']}
query = input("Look up database on whom? > ")
for (name, info) in Family.items():
if name in query or name.lower() in query:
print("{} is {}".format(name, info))
This ^ works. However, when I tried to add an ELSE clause, to deal with non-existent entries, I get this.
else:
print ('Value not found!')
It prints the Value not found! many times before bringing up the value. If I try to add a 'go back to start' function it doesn't even bring up a registered value. I know this is because it is a loop and iterates over the dict one by one; so like 1)jim is true then 2) ned is false.
How do I improve this code to make it: -able to give an error about a non-existent entry and then restart the program. Thanks.
You will need to take care of case insensitivity in your code. Iterate through the list to ensure that the name exists before continuing:
Family = {'Jim' : ['cool guy', 'has facial hair'],
'Ned' : ['hot stuff', ' wears Tees']}
names = [name.lower() for name in Family]
def find(query):
if query.lower() in names:
info = [Family[n] for n in Family if n.lower() == query.lower()]
print('{} is {}'.format(
query, info
))
else:
print('{} not found'.format(query))
If you try it with the following sample:
find('Ned')
find('ned')
find('no ned')
You will get the following results:
Ned is [['hot stuff', ' wears Tees']]
ned is [['hot stuff', ' wears Tees']]
no ned not found
This is one way to do it:
Family = {'Jim' : ['cool guy', 'has facial hair'],
'Ned' : ['hot stuff', ' wears Tees']}
query = input("Look up database on whom? > ")
if query in Family.keys():
for (name, info) in Family.items():
if name in query or name.lower() in query:
print("{} is {}".format(name, info))
else:
print "Print Something - Not in Family"

Categories