I want to create a function to filter which files I want to open and which months and day specifically. That way, the users need to input which city (files) they want to analyze on which particular month or day. However, I want the user to be able to input something that is not case sensitive.
For example, the user can input 'chicago'/'CHICAGO"/"ChIcAgO" and the it still give you the right output and not the error handling message. Here is the code I use:
def get_filters ():
city_options = ['Chicago','New York City','Washington']
month_options = ['January','February','March','April','May','June','All']
day_options = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday','All']
while True:
try:
city = city_options.index(input('\nInsert name of the city to analyze! (Chicago, New York City, Washington)\n'))
month = month_options.index(input('\nInsert month to filter by or "All" to apply no month filter! (January, February, etc.)\n'))
day = day_options.index(input('\nInsert day of the week to filter by or "All" to apply no day filter! (Monday, Tuesday, etc.)\n'))
return city_options[city].lower(), month_options[month].lower(), day_options[day].lower()
except ValueError:
print ("Your previous choice is not available. Please try again")
def load_data (city,month,day):
#load data file into DataFrame
df = pd.read_csv(CITY_DATA[city].lower())
#convert start time column (string) to datetime
df['Start Time']=pd.to_datetime(df['Start Time'])
#create new column to extract month and day of the week from start time
df['Month'] = df['Start Time'].dt.month
df['Day_of_Week'] = df['Start Time'].dt.weekday_name
#filter by month if applicable
if month.lower()!= 'All':
#use the index of the month list to get corresponding into
months = ['January', 'February', 'March', 'April', 'May', 'June']
month = months.index(month) + 1
#filter by month to create new dataframes
df = df[df['Month'] == month]
if day.lower()!= 'All':
#filter by day_of_week to create new DataFrames
df =df[df['Day_of_Week'] == day]
return(df)
The best way to do so is just take the required input and convert it into the required case.
Use the inbuilt functions of python
variable.lower()
or
variable.upper()
You should use str.casefold to remove case sensitivity. As per the docs, this is stricter than str.lower:
str.casefold()
Return a casefolded copy of the string. Casefolded strings may be used
for caseless matching.
Casefolding is similar to lowercasing but more aggressive because it
is intended to remove all case distinctions in a string. For example,
the German lowercase letter 'ß' is equivalent to "ss". Since it is
already lowercase, lower() would do nothing to 'ß'; casefold()
converts it to "ss".
For example:
x = 'ßHello'
print(x.casefold())
sshello
I just started learning Python in December 2021.
I encountered a similar problem while writing the codes for a 'choose your own fantasy game".
To remove the case sensitivity, use the string.lower() or string.upper() function. Now, this answer is no different from the first answer to this question.
So, what's special here?
Well, if you are testing the answer from the user, your if-statement must have the same case as the case you are converting to e.g
answer = input("What is rat? 'Animal' or 'Food' ")
3)if answer.lower() == "animal":
print("Congratulations. You win! ")
5) else:
print("Sorry, you lose! ")
OR:
answer = input("What is rat? 'Animal' or 'Food' ")
3)if answer.upper() == "ANIMAL":
print("Congratulations. You win! ")
5) else:
print("Sorry, you lose! ")
N.B: No matter how the user types their answer (ANIMAL, ANimal, animal), if the answer is correct, he wins. So long the test case function is the same as the case string (line 3) to be tested.
I hope this helps!
I am new too but I think you should look at string functions. Presuming you use python 3 since you use input and get no ValueError, you can just add .lover().title() after the parentheses of the input
Example:
city = city_options.index(input('\nInsert name of the city to analyze! (Chicago, New York City, Washington)\n').lower().title())
Should do the trick as like If you input cHIcaGO it will be converted to Chicago instantly.
Hope it helps!
Edit:(After correcting misspelling of lower() function tried it on webbrowser, pycharm and Python itself. Works just fine for me(I'm using python 2.7 so I corrected all inputs as raw_input,If you are using python 3 you don't have to change them. ).)
Related
Basically, I am new to programming and I sign up for a python course. I receive an exercise asking as follow:
Build a function that returns, given an arbitrary birth year, the Chinese zodiac sign corresponding to that calendar year. You start from a dictionary of Chinese zodiac signs from 2001-2012 (covering the whole 12-sign cycle)
So my idea is to create a dictionary,
d={2001:'Snake',2002:'Horse',2003:'Goat',2004:'Monkey',2005:'Rooster',2006:'Dog',
2007:'Pig',2008:'Rat',2009:'Ox',2010:'Tiger',2011:'Rabbit',2012:'Dragon'}
And I begin with the for statement
def year(x):
for x in d.keys:
if x=d.keys:
print d.value
else:
x..
I basically have no idea how to approach the next step. Can someone please me some direction?
You are on the right track. You can create a dictionary to store the Chinese Zodiac Signs. Since there are 12 of them and to make the math easier, let's get the modulus value of 12 for each year. That makes mod 0 = Monkey,... mod 11 = Goat.
With that, you can do year % 12 will result with a number that we can use to extract the value from the dictionary d. The way to extract the value from the dictionary is dict[key]. In our case it will be d[0] will give Monkey.
With that, we can write the program as follows:
#define the dictionary with keys. Numbers 0 thru 11 as keys and Zodiac sign as values
d={0:'Monkey',1:'Rooster',2:'Dog',3:'Pig',4:'Rat',5:'Ox',
6:'Tiger',7:'Rabbit',8:'Dragon',9:'Snake',10:'Horse',11:'Goat'}
#define a function that receives the birth year, then returns the Zodiac sign
#as explained earlier we do dict[key]
#year%12 will give the key to use
def chinese_yr(cy):
return d[cy%12]
#get an input from the user. To ensure the value is an int,
#use the statement within a try except statement
while True:
try:
yr = int(input ('enter year :'))
break
except:
print ('Invalid entry. Please enter year')
#call the function with the year as argument
print (chinese_yr(int(yr)))
The output of this will be:
enter year :2011
Rabbit
enter year :2001
Snake
enter year :2020
Rat
enter year :2021
Ox
First thing first, thank you to Jakob and Steve, I have never thought of using modulus. So I adjusted my dictionary and my coded.
d={9:'Snake',10:'Horse',11:'Goat',0:'Monkey',1:'Rooster',2:'Dog',
3:'Pig',4:'Rat',5:'Ox',6:'Tiger',7:'Rabbit',8:'Dragon'}
def get_Chinese_zodiac(x):
for x in d:
x=x%12
return d[x]
Funny thing is, my code can only return "Dragon".
I'm in the process of learning how to code in Python and have been doing numerous tasks to help solidify info.
I had 1 issue - I am creating code that will take the date (dd/mm/yyyy) and then the program will validate the data (i.e checking if there are errors in the field and if so, naming the error type; if no errors are found, the user is told the input was correct) - just some data validation practise.
Where I'm getting stuck is just assigning the variables - I have typed and tested the day and year correctly but I cant manage to get the 4th and 5th integer of the variable date for the month variable.
Here is my code that I am first producing to make sure the integers I will be working with are correct:
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
dayDate = str(date)[:2]
# could also be written as dayDate = str(date)[:-8]
#defines where to locate month in user input
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
#defines where to locate year in user input
yearDate = str(date)[-4:]
print(yearDate)
print(finalMonth)
print(dayDate)
From this code, the variables yearDate and dayDate present me with the values I want but the finalMonth is where i'm getting stuck. I've looked all over Google but can't seem to find the solution. If you do know how to solve my issue, I would really appreciate it if you could send the proper way to go about this and why you did what, as I am still kind of a newb in Python :)
I know the error is the function I've created for finding the month values, but that's precisely where I need help.
Thank you!
EDIT:
Sorry! I am new to Stack overflow so I didn't know.
so the code:
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
print(finalMonth)
returns the output '/' but what I am trying to get is for example you input '26/01/2021' and the variable finalMonth will give '01' - this code produces '/'. I am not sure what method should be used to get the month value.
you can use split() to create a list from input as below
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
day, month, year = date.split("/")
print( day, month, year )
The quick answer to your error you were having is change
date[(len(date)//2)] to date[3:5]
After your clarification, I put together an example showing how you can handle error checking. :)
import datetime as dt
# the -> is to hint at the type of variable this function will return, this is not needed, but good practice
def get_date_from_user() -> dt.datetime:
# This will keep looping until correct gets changed to True
correct = False
while correct is False:
user_input = input("Please enter the date in format dd/mm/yyyy: ")
try:
# This part can be done in a lot of ways, I did it this way to demonstrate a condensed way and type conversions
date = dt.datetime(int(user_input[-4:]), int(user_input[:2]), int(user_input[3:5]))
correct = True # If the datetime was made successfully, set the loop to TRUE to escape
except ValueError as err:
print(err)
return date
date = get_date_from_user()
print(f'Day: {date.day} Month: {date.month} Year: {date.year}')
For handling dates though I highly recommend checking out Pendulum. With it you could do something like this:
import pendulum
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
dayDate = date.day
finalMonth = date.month
yearDate = date.year
It will throw an error if it cant parse what they typed in as well. If you wrap it in a Try and Except cause you can catch that too like below:
Python error handeling
import pendulum
try:
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
except ValueError as err:
print(err)
dayDate = date.day
finalMonth = date.month
yearDate = date.year
I'm fairly new to coding in Python. For a personal project, I'm looking for different ways to retrieve birthdays and days of death from a list of Wikipedia pages. I am using wikipedia package.
One way I try to achieve that is by iterating over the Wikipedia summary and returning the index from when I count four digits in a row.
import wikipedia as wp
names = ('Zaha Hadid', 'Rem Koolhaas')
wiki_summary = wp.summary(names)
b_counter = 0
i_b_year = []
d_counter = 0
i_d_year = []
for i,x in enumerate(wiki_summary):
if x.isdigit() == True:
b_counter += 1
if b_counter == 4:
i_b_year = i
break
else:
continue
else:
b_counter = 0
So far, that works for the first person in my list but I would like to iterate over all the names in my names list. Is there a way to use the for loop to find the index and use a for loop to iterate over the names?
I know there are other ways like parsing to find the bday tags, but I would like to try a couple of different solutions.
You are trying to:
Declare two empty lists to store birth year and death year of each person.
Get Wikipedia summary of each person from a tuple.
Parse first two numbers with 4 digits from the summary and append them to birth year and death year list.
The problem is that summary of the persons may not include birth year and death year as first two 4 digit numbers. For example Rem_Koolhaas's wikipedia summary includes his birth year as first 4 digit number but second 4 digit number is in this line: In 2005, he co-founded Volume Magazine together with Mark Wigley and Ole Bouman.
We can see that, the birth_year and death_year list may not include accurate information.
Here is the code that does what you are trying to achieve:
import wikipedia as wp
names = ('Zaha Hadid', 'Rem Koolhaas')
i_b_year = []
i_d_year = []
for person_name in names:
wiki_summary = wp.summary(person_name)
birth_year_found = False
death_year_found = False
digits = ""
for c in wiki_summary:
if c.isdigit() == True:
if birth_year_found == False:
digits += c
if len(digits) == 4:
birth_year_found = True
i_b_year.append(int(digits))
digits = ""
elif death_year_found == False:
digits += c
if len(digits) == 4:
death_year_found = True
i_d_year.append(int(digits))
break
else:
digits = ""
if birth_year_found == False:
i_b_year.append(0)
if death_year_found == False:
i_d_year.append(0)
for i in range(len(names)):
print(names[i], i_b_year[i], i_d_year[i])
Output:
Zaha Hadid 1950 2016
Rem Koolhaas 1944 2005
Disclaimer: in the above code, I have appended 0 if two 4 digit numbers are not found in the summary of any person. As I have already mentioned there is no assertion that wikipedia summary will list a person's birth year and death year as first two 4 digits numbers the lists may include wrong information.
I am not familiar with the Wikipedia package, but it seems like you could just iterate over the names tuple:
import Wikipedia as wp
names = ('Zaha Hadid', 'Rem Koolhaas')
i_b_year = []
for name in names: #This line is new
wiki_summary = wp.summary(name) #Just changed names for name
b_counter = 0
d_counter = 0
i_d_year = []
for i,x in enumerate(wiki_summary):
if x.isdigit() == True:
b_counter += 1
if b_counter == 4:
i_b_year.append(i) #I am guessing you want this list to increase with each name in names. Thus, 'append'.
break
else:
continue
else:
b_counter = 0
First of all, your code won't work due to several reasons:
Importing wikipedia will only work with first lowercase letter import wikipedia
summary method accepts strings (in your case names), so you would have to call it for every name in a set
All of this aside, let's try to achieve what you're trying to do:
import wikipedia as wp
import re
# First thing we see (at least for pages provided) is that dates all share the same format:
# For those who are no longer with us 31 October 1950 – 31 March 2016
# For those who are still alive 17 November 1944
# So we have to build regex patterns to find those
# First is the months pattern, since it's quite a big one
MONTHS_PATTERN = r"January|February|March|April|May|June|July|August|September|October|November|December"
# Next we build our date pattern, double curly braces are used for literal text
DATE_PATTERN = re.compile(fr"\d{{1,2}}\s({MONTHS_PATTERN})\s\d{{,4}}")
# Declare our set of names, great choice of architects BTW :)
names = ('Zaha Hadid', 'Rem Koolhaas')
# Since we're trying to get birthdays and dates of death, we will create a dictionary for storing values
lifespans = {}
# Iterate over them in a loop
for name in names:
lifespan = {'birthday': None, 'deathday': None}
try:
summary = wp.summary(name)
# First we find the first date in summary, since it's most likely to be the birthday
first_date = DATE_PATTERN.search(summary)
if first_date:
# If we've found a date – suppose it's birthday
bday = first_date.group()
lifespan['birthday'] = bday
# Let's check whether the person is no longer with us
LIFESPAN_PATTERN = re.compile(fr"{bday}\s–\s{DATE_PATTERN.pattern}")
lifespan_found = LIFESPAN_PATTERN.search(summary)
if lifespan_found:
lifespan['deathday'] = lifespan_found.group().replace(f"{bday} – ", '')
lifespans[name] = lifespan
else:
print(f'No dates were found for {name}')
except wp.exceptions.PageError:
# Handle not found page, so that code won't break
print(f'{name} was not found on Wikipedia')
pass
# Print result
print(lifespans)
Output for provided names:
{'Zaha Hadid': {'birthday': '31 October 1950', 'deathday': '31 March 2016'}, 'Rem Koolhaas': {'birthday': '17 November 1944', 'deathday': None}}
This approach is inefficient and has many flaws, like if we get a page with dates fitting our regular expression, yet not being birthday and death day. It's quite ugly (even though I've tried my best :) ) and you'd be better off parsing tags.
If you're not happy with date format from Wikipedia, I suggest you look into datetime. Also, consider that those regular expressions fit those two specific pages, I did not conduct any research on how dates might be represented in Wikipedia. So, if there are any inconsistencies, I suggest you stick with parsing tags.
I am making a basic date converter and I need to update the the date every time the user enters an invalid date and is asked to input again. From this function below, I need both the object day and year returned.
def day_valid (month, dates, feb_day, month_days):
day = int(dates[2:4])
while month_days == 31 and day > 31:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == 31 and day < 32:
break
while month_days == 30 and day > 30:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == 30 and day < 31:
break
while month_days == feb_day and day > feb_day:
print ("Invalid day input.")
print()
dates = input_date()
day = int(dates[2:4])
if month_days == feb_day and day <= feb_day:
break
return day
When a user types in 00102002 in MMDDYYYY format, there is no month. So the user is prompted to enter again, entering 01102005. The code still displays the date as 10 January 2002 and not 2005 .
If any one needs clarification on the code, please ask!
My main function:
def main():
loop = "Y"
print()
print("Welcome to Date Converter!")
print()
while loop.upper () == "Y" :
dates = input_date()
year = int(dates[4:])
month = month_valid(dates)
feb_day = feb_days(year)
month_days = month_Days(month, feb_day)
day = day_valid(month, dates, feb_day, month_days)
month_str = month_names(month)
print()
print("The date is " + str(day) + " " + month_str + " " + str(year))
loop = str(input ("Do you want to re-run this program? Y/N: "))
main()
This sounds first of all like an XY Problem: someone wants to do X, and comes up with a solution requiring doing Y. They need help with Y, so request help to do Y. However, it turns out that Y is not an appropriate solution. By recognizing the XY Problem and asking how to do X instead, the person gets better help and more insight into X.
XY Problems also often look suspiciously like homework problems, since those are often of the form "write a program that does X, by doing Y".
It's OK to pose a question that you want to do X and tried to solve it using Y.
Anyway, that's why you're probably going to get low-effort answers. I'll make the effort :)
Anyway, going with the Y question :)
There is a readability practice that considers tuples harmful because you don't know what the purpose of the items in the tuple are. Consider instead creating an object that holds the things, each with its own attribute, and then return that.
Since you stated that you needed day and year returned:
class DayAndYear(object):
def __init__(self, day, year):
self.day = day
self.year = year
And that's how you do it without making a tuple, and it increases the readability of your program, such as it is.
Now, going with the unstated X question:
without knowing what month_valid does,
assuming feb_days returns the number of days in February of the given year,
assuming month_Days returns the number of days in the given month when it isn't February,
it seems that you want a function that will check if a string is a valid MMDDYYYY string.
def is_valid_date(s):
"""Checks if the given date is a valid MMDDYYYY string.
Args:
s (str): A date to check.
Returns:
bool: True if the date is valid, False otherwise.
"""
if len(s) != 8:
return False
try:
date = int(s[:2])
month = int(s[2:4])
year = int(s[4:])
except ValueError:
return False
if month < 1 and month > 12:
return False
if month == 2:
days_in_month = days_in_february(year)
else:
days_in_month = days_in_month(month)
return date >= 1 and date <= days_in_month
def print_date(s):
"""Prints the given MMDDYYYY date, assuming it has already been checked for validity.
Args:
s (str): A date to print.
"""
print("The date is {:d} {:s} {:d}.".format(
int(s[2:4]), month_name(int(s[:2])), int(s[4:])))
I'd like to highlight a few general techniques to make your programs read better:
We don't know X. A well-posed question is one with specifications for the input and output of the program.
I've used verbose, readable function names.
I've used function comments, complete with args, arg types, and return values so there's no guessing about what things do.
I've chosen a split between checking validity and printing an already valid string. You can combine them. You can also return a string rather than print the date, and return instead the sentinel value None if the date was not valid.
Don't compute any more than you have to. Note the early returns.
No doubt there are library functions that will do this, but I've assumed you don't want to use any library functions.
The short key concepts:
Readability: Programs should be almost as easy to read as prose in your native language.
Readability: Function names should be descriptive.
Readability: Comment your code.
Readability: Choose a consistent format for functions and stick with it ("month_Days" vs "feb_days")
Efficiency: Return early.
Testability: Specify well what your program does in terms of inputs and outputs, give examples of good and bad inputs.
Effectiveness: Use library functions.
Stackoverflowness: Consider if your problem is an XY problem.
I need a program that would let a person enter a person's name and his birth year (5 people only).
The information is written into two lists - one with names and the other with years.
Then the program needs to remove the youngest person (or youngest people).
The final result needs to be printed out in a .txt file.
This is what I have so far:
names = []
ages = []
def names_ages():
while True:
name_age = input("Enter your name and birth year: ")
name_age.split()
print(name_age)
I don't know if I'm going into the right direction or not, could somebody suggest something?
I am going to assume that you are expecting first name and the year to be separated by a space like so.
"andrew 1996"
if so, you are going to want to split the input on space (to have the first entry correspond to "andrew" and the second to correspond to "1996"
response = name_age.split(" ")
Now you can add these values to the arrays that you defined up above (or you could use a python dictionary which I think would be better suited for this problem) https://docs.python.org/2/tutorial/datastructures.html#dictionaries
names.append(response[0])
ages.append(int(response[1]))
You are going to have to decide when to stop accepting names, which you would put in your while loop condition(right now it is running forever) Perhaps wait until the user input is "stop" or something of that nature.
That should get you in the correct direction, comment if you have any questions
name = []
year = []
x=0
while x <3:
x += 1
user = name.append(raw_input("enter name"))
user_year = year.append(raw_input("enter DOB"))
o = []
for i in zip(year,name):
o.append(i)
o.sort()
o.remove(o[0])
print o
This might one from of the solutions from many possible.