Python elif to nested if - python

I have made this program using elif statements and am just curious on how it would be done using nested ifs instead.
The user has to input a number and the program will tell them which month it is and how many days are in it.
month_num = int(input("Enter the number of a month (Jan = 1) : "))
if month_num == 1:
print(month_num, "is Feburary, and has 29 days.")
elif month_num == 2:
print(month_num, "is January, and has 31 days.")
elif month_num == 3:
print(month_num, "is March, and has 31 days.")
elif month_num == 4:
print(month_num, "is April, and has 30 days.")
elif month_num == 5:
print(month_num, "is May, and has 31 days.")
elif month_num == 6:
print(month_num, "is June, and has 30 days.")
elif month_num == 7:
print(month_num, "is July, and has 31 days.")
elif month_num == 8:
print(month_num, "is August, and has 31 days.")
elif month_num == 9:
print(month_num, "is September, and has 30 days.")
elif month_num == 10:
print(month_num, "is october, and has 31 days.")
elif month_num == 11:
print(month_num, "is November, and has 30 days.")
elif month_num == 12:
print(month_num, "is december, and has 31 days.")
else:
print(month_num, "Is not a valid number")

Neither are a good solution. You'd be better off creating a dictionary.
Assuming f-strings are available (Python >= 3.6). If not these can be easily converted to use .format:
month_num = int(input("Enter the number of a month (Jan = 1) : "))
d = {1: ('January', 31),
2: ('February', 29),
...
}
try:
month_name, num_of_days = d[month_num]
print(f'{month_num} is {month_name}, and has {num_of_days} days')
except KeyError:
print(month_num, "Is not a valid number")
Also note that February does not always have 29 days.

You can use calendar, i.e.:
import calendar as cal
from datetime import date
m = int(input("Enter the number of a month (Jan = 1) : "))
if m in range(1,13):
print(f"{m} is {cal.month_name[m]} and has {cal.monthrange(date.today().year, m)[1]} days.")
1 is January and has 31 days.
2 is February and has 29 days.
3 is March and has 31 days.
4 is April and has 30 days.
5 is May and has 31 days.
6 is June and has 30 days.
7 is July and has 31 days.
8 is August and has 31 days.
9 is September and has 30 days.
10 is October and has 31 days.
11 is November and has 30 days.
12 is December and has 31 days.
Demo

Related

problem with if else loop for a month and days problem

why do I get the wrong output for the code below, I've put the output below
(some might suggest using date-time module, I'm going with this method due to some complications with the main program)
months = [1,2,3,4,5,6,7,8,9,10,11,12]
for month in months:
if month == {1,3,5,7,9,11}:
days= 31
print(days)
elif month == {4,6,8,10,12}:
days = 30
print(days)
else :
days = 28
print(days)
I get this output
28
28
28
28
28
28
28
28
28
28
28
28
Question approach
You are checking if an integer is equal to a set. You want to check if the integer is in the set. By the way, the sets you use are wrong (fixed here) and february may have 29 days (not fixed in this solution).
for month in range(1, 13):
if month in {1, 3, 5, 7, 8, 10, 12}:
days = 31
elif month in {4, 6, 9, 11}:
days = 30
else :
days = 28
print(f"{month:2}: {days}")
1: 31
2: 28
3: 31
4: 30
5: 31
6: 30
7: 31
8: 31
9: 30
10: 31
11: 30
12: 31
Calendar approach
Another solution is to use the calendar module which fixed the 29 days on february issue.
import calendar
for month in range(1, 13):
days = calendar.monthrange(2020, month)[1]
print(f"{month:2}: {days}")
1: 31
2: 29
3: 31
4: 30
5: 31
6: 30
7: 31
8: 31
9: 30
10: 31
11: 30
12: 31

Is there a way to break from a range() function at a specific value?

I am new to programming in python and am trying to design a calendar that starts the month depending on the selected start day.
However, I don't know how to stop the print once the number of days has been exceeded(e.g breaks at days=31 when month=="January")
The printed values must be right-aligned additionally.
Here is how I first approached it:
month=input("Enter the month: ")
if month=="January" or month=="March" or month=="May" or month=="July" or month=="August" or month=="October" or month=="December":
days=31
else:
days=30
if month=="February":
days=28
Start_day=input("Enter the start day: ")
print(month)
print("Mo","Tu","We","Th","Fr","Sa","Su")
if Start_day == "Monday":
i=1
if Start_day == "Tuesday":
i=0
if Start_day == "Wednesday":
i=-1
if Start_day == "Thursday":
i=-2
if Start_day == "Friday" :
i=-3
if Start_day == "Saturday":
i=-4
if Start_day == "Sunday":
i=-5
j=1
for j in range(i,days,7):
print(str(j).rjust(2," "),str(j+1).rjust(2," "),str(j+2).rjust(2," "),str(j+3).rjust(2," "),str(j+4).rjust(2," "),str(j+5).rjust(2," "),str(j+6).rjust(2," "))
You could encode it instead as
j=1
for j in range(i,days,7):
for i in range(0,7):
if j+i>days: break
print(str(j+i).rjust(2," "),end=' ')
print('')
This would be called "breaking out of a loop" rather than "breaking from a range function." There is no way to "break from a range function."
Can I suggest overhauling this a bit to be more efficient? You can use dicts and define a custom function to handle the date formatting to prevent some repetition.
To answer your question, you can evaluate the date number during the final loop:
for j in range(i,days,7):
# add to j value via range() and adjust()
# (defined above) to prevent repetition
for k in range(7):
if j + k > 0 and j + k <= days:
print(adjust(j + k), end = ' ') # don't print new line
else:
# print spaces if the number is <1 or >days
print(' ', end = '')
# print new line for a new week
print('\n', end = '')
Full example:
# function to format dates later
def adjust(val):
return str(val).rjust(2," ")
# get inputs
month=input("Enter the month: ")
start_day=input("Enter the start day: ")
# map months to days in a dict
month_to_days={"january":31,
"march":31,
"may":31,
"july":31,
"august":31,
"october":31,
"december":31,
"february":28,
"april":30,
"june":30,
"september":30,
"october":30
}
# map weekdays to int
days_to_int={"monday":1,
"tuesday":0,
"wednesday":-1,
"thursday":-2,
"friday":-3,
"saturday":-4,
"sunday":-5
}
# get the day amount based on the entry, ignoring case
days=month_to_days[month.lower()]
# get the int based on the entry, ignoring case
i=days_to_int[start_day.lower()]
# print month and day headers
print(month)
print("Mo","Tu","We","Th","Fr","Sa","Su")
for j in range(i,days,7):
# add to j value via range() and adjust()
# (defined above) to prevent repetition
for k in range(7):
if j + k > 0 and j + k <= days:
print(adjust(j + k), end = ' ') # don't print new line
else:
# print spaces if the number is <1 or >days
print(' ', end = '')
# print new line for a new week
print('\n', end = '')
Output:
Enter the month: january
Enter the start day: monday
january
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
>>>
Enter the month: june
Enter the start day: wednesday
june
Mo Tu We Th Fr Sa Su
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Before you print after your for loop just have an if statement to check for your condition and before you print add a break statement.
Something like:
if statement:
break

Udacity's finish daysBetweenDates answer might be wrong

There might be a bug in this lesson.
I'm trying to move forward without needing to watch the answer videos for the daysBetweenDates quiz.
Long story short:
I figured out the code and it works for all test cases, except one.
The error was odd. The difference between the number of days between dates I got and the answer according to Udacity. My notion is that if there's error in my code, the difference between the answer I got and Udacity's expected answer would be more than 1 because the error should be recurring.
I tried to compute the number of days between dates using a different approach. I got the number my program computed.
So the question is, is the number of days between dates between 1900,1 ,1 and 1999,12, 31 really 36523(Udacity's answer) or 36524(my answer)
Here's my complete code
I recommend you try it on your interpreter to check if Udacity's answer for the last test case is correct.
# Credit goes to Websten from forums
#
# Use Dave's suggestions to finish your daysBetweenDates
# procedure. It will need to take into account leap years
# in addition to the correct number of days in each month.
number_of_days_in_month = 30
def nextDay(year, month, day):
"""Simple version: assume every month has 30 days"""
number_of_days_in_month = setDaysInMonth(month, year)
if day < number_of_days_in_month:
return year, month, day + 1
else:
if month == 12:
return year + 1, 1, 1
else:
return year, month + 1, 1
def dateIsBefore(year1, month1, day1, year2, month2, day2):
"""Returns True if year1-month1-day1 is before year2-month2-day2. Otherwise, returns False."""
if year1 < year2:
return True
if year1 == year2:
if month1 < month2:
return True
if month1 == month2:
return day1 < day2
return False
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
"""Returns the number of days between year1/month1/day1
and year2/month2/day2. Assumes inputs are valid dates
in Gregorian calendar."""
# program defensively! Add an assertion if the input is not valid!
assert not dateIsBefore(year2, month2, day2, year1, month1, day1)
number_of_days_between_dates = 0
while dateIsBefore(year1, month1, day1, year2, month2, day2):
year1, month1, day1 = nextDay(year1, month1, day1)
number_of_days_between_dates += 1
print number_of_days_between_dates
return number_of_days_between_dates
def setDaysInMonth(month1, year1):
if isLeapYear(year1) == False:
if month1 == 1:
number_of_days_in_month = 31
if month1 == 3:
number_of_days_in_month = 31
if month1 == 5:
number_of_days_in_month = 31
if month1 == 7:
number_of_days_in_month = 31
if month1 == 8:
number_of_days_in_month = 31
if month1 == 10:
number_of_days_in_month = 31
if month1 == 12:
number_of_days_in_month = 31
if month1 == 4:
number_of_days_in_month = 30
if month1 == 6:
number_of_days_in_month = 30
if month1 == 9:
number_of_days_in_month = 30
if month1 == 11:
number_of_days_in_month = 30
if month1 == 2:
number_of_days_in_month = 28
return number_of_days_in_month
else:
if month1 == 1:
number_of_days_in_month = 31
if month1 == 3:
number_of_days_in_month = 31
if month1 == 5:
number_of_days_in_month = 31
if month1 == 7:
number_of_days_in_month = 31
if month1 == 8:
number_of_days_in_month = 31
if month1 == 10:
number_of_days_in_month = 31
if month1 == 12:
number_of_days_in_month = 31
if month1 == 4:
number_of_days_in_month = 30
if month1 == 6:
number_of_days_in_month = 30
if month1 == 9:
number_of_days_in_month = 30
if month1 == 11:
number_of_days_in_month = 30
if month1 == 2:
number_of_days_in_month = 29
return number_of_days_in_month
def isLeapYear(year1):
if year1 % 4 == 0:
return True
return False
def numberOfLeapYears(year1, year2):
number_of_leap_years = 0
while year1 < year2:
if year1 % 4 == 0:
number_of_leap_years += 1
year1 += 1
else:
year1 += 1
#print "number of leap years: " + str(number_of_leap_years)
return number_of_leap_years
def numberOfNonLeapYears(year1, year2):
number_of_non_leap_years = 0
while year1 < year2:
if year1 % 4 == 0:
year1 += 1
else:
number_of_non_leap_years += 1
year1 += 1
#print "number of non leap years: " + str(number_of_non_leap_years)
return number_of_non_leap_years
def numberOfDays(year1, year2):
number_of_leap_years = numberOfLeapYears(year1, year2)
print number_of_leap_years
number_of_non_leap_years = numberOfNonLeapYears(year1, year2)
print number_of_non_leap_years
number_of_days = 0
number_of_days = number_of_leap_years * 366 + number_of_non_leap_years * 365
#print number_of_days
return number_of_days
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523),
((1900,1,1,1910,1,1), 3653)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()
#print isLeapYear(1900)
#print 366*3 + 365*7
#print numberOfLeapYears(1900, 1999)
#print numberOfNonLeapYears(1900, 1999)
print numberOfDays(1900, 2000)
You are using a naive test for Leap Year ( %4). But there are additional rules to leap years.
Leap year is any year evenly divisible by 4, unless it is divisible by 100 (then it is not a leap year), unless it is divisible by 400 (Then it is a leap year).
Thus 1500, 1700, 1800, 1900 were not leaps years but 1600 and 2000 were leap years.
A simple Python version:
def is_leap_year(year):
if year % 400 == 0:
return True
if year % 4 == 0 and not year % 100 == 0:
return True
return False

Days old udacity

I have a problem in these two casesprint daysBetweenDates(2011, 1, 1, 2012, 8, 8)
print daysBetweenDates(1900,1,1, 1999,12, 31)when I put them with the other test cases I got a wrong answer by 1 day extra and sometimes by 2 days.sometimes one of them give me the right answer but it also appears asTest with data:(2011, 1, 1, 2012,8,8)failed
Test with data: (1900, 1, 1, 1999, 12, 31) failed but when I test each case alone i got the right answer.
daysofmonths = [ 0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def leap_year(year):
leap_day = 366
common_day = 365
if year % 4 != 0:
return common_day
elif year % 100 != 0:
return leap_day
elif year % 400 !=0:
return common_day
else:
return leap_day
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
#code for same year
if year1 == year2:
if month1 == month2:
return day2 - day1
days = daysofmonths[month1] - day1
month1 = month1 + 1
while month1 < month2:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
month1 = month1 + 1
return days + day2
################################################
days = daysofmonths[month1] - day1
month1 = month1 + 1
while month1 <= 12:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
month1 = month1 + 1
#print days
year1 = year1 + 1
###########################################################
days = days + day2
month2 = month2 - 1
while month2 >= 1:
if leap_year(year2) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month2]
month2 = month2 - 1
#print days
year2 = year2 - 1
###########################################################
while year1 <= year2:
days = days + leap_year(year1)
year1 = year1 + 1
return days
print daysBetweenDates(2011, 1, 1, 2012, 8, 8)
print daysBetweenDates(1900,1,1, 1999,12, 31)
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()
when you do:
daysofmonths[2] = 29
it changes the element in the list, which then is used for every subsequent call, if you added print(daysofmonths[2]) in between the test cases you would see that it is always 29 after the first case that needs to check February, so instead of conditionally changing the list with:
if leap_year(year1) == 366:
daysofmonths[2] = 29
days = days + daysofmonths[month1]
just conditionally add to days:
if leap_year(year1) == 366 and month1 == 2:
days = days + 29
else:
days = days + daysofmonths[month1]
then do the same thing lower down with year2 and month2 (I would highly recommend you separate your code into more functions as a lot of it is very repetitive)
This is the only post I found here on this particular problem so I thought I would share my solution.
#days in the months of a non leap year
daysOfMonths = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
#determine if a year is a leap year
def is_leap_year(year1):
year = True
if year1 % 4 != 0:
year = False
elif year1 % 100 != 0:
year = True
elif year1 % 400 != 0:
year = False
else: year = True
return year
#returns the days in the given month of the given year
#I was trying to do something similar to the OP until I read this post
def days_in_month(year, month):
days = 0
if is_leap_year(year) and month == 2:
days += 29
else:
days += daysOfMonths[month - 1]
return days
#itterates through each month starting at year1 month1
#up to but not including month2 of year2 and
#returns the total number of days in that period
def total_days(year1, month1, year2, month2):
days = 0
while year1 < year2 or month1 < month2:
days += days_in_month(year1, month1)
month1 += 1
if month1 == 13:
year1 += 1
month1 = 1
return days
def daysBetweenDates(year1, month1, day1, year2, month2, day2):
days = total_days(year1, month1, year2, month2)
#because I included the beginning month I have to subtract day1
#because I did not include the final month I have to add day2
return days - day1 + day2
#I used print statements here to troubleshoot
#print days_in_month(2012, 1)
#print daysBetweenDates(2012, 1, 1, 2012, 2, 28)
#print daysBetweenDates(2012, 1, 1, 2012, 3, 1)
#print daysBetweenDates(2011,6,30,2012,6,30)
#print daysBetweenDates(2011,1,1,2012,8,8)
#print daysBetweenDates(1900,1,1,1999,12,31)
def test():
test_cases = [((2012,1,1,2012,2,28), 58),
((2012,1,1,2012,3,1), 60),
((2011,6,30,2012,6,30), 366),
((2011,1,1,2012,8,8), 585 ),
((1900,1,1,1999,12,31), 36523)]
for (args, answer) in test_cases:
result = daysBetweenDates(*args)
if result != answer:
print "Test with data:", args, "failed"
else:
print "Test case passed!"
test()

Print month using the month and day

I need to print month using the month and day. But I cannot seem to move the numbers after '1' to the next line using Python.
# This program shows example of "November" as month and "Sunday" as day.
month = input("Enter the month('January', ...,'December'): ")
day = input("Enter the start day ('Monday', ..., 'Sunday'): ")
n = 1
if month == "January" or month == "March" or month == "May" or month == "July" or month == "August" or month == "October" or month == "December":
x = 31
elif month == "February":
x = 28
else:
x = 30
print(month)
print("Mo Tu We Th Fr Sa Su")
if (day == "Sunday"):
print(" ", end='')
for i in range (1, 7):
for j in range (1, 8):
while n != x+1:
print('%2s' % n, end=' ')
n = n + 1
break
print()
Output looks like this:
November
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Some changes.
Instead of having a nested loop, just have a single loop that prints all the dates. Then, inside that loop, make the decision about whether to end the line (if the date you just printed corresponded to a Sunday).
Also, the # of days in month look-up is a bit cleaner, and you now handle more "days" than just Sunday:
day = "Monday"
month = "March"
# Get the number of days in the months
if month in ["January", "March", "May", "July", "August", "October", "December"]:
x = 31
elif month in ["February"]:
x = 28
else:
x = 30
# Get the number of "blank spaces" we need to skip for the first week, and when to break
DAY_OFF = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
off = DAY_OFF.index(day)
print(month)
print("Mo Tu We Th Fr Sa Su")
# Print empty "cells" when the first day starts after Monday
for i in range(off):
print(" ", end=' ')
# Print days of the month
for i in range(x):
print("%2d" % (i+1), end=' ')
# If we just printed the last day of the week, print a newline
if (i + off) % 7 == 6: print()
March/Monday
March
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
March/Sunday
March
Mo Tu We Th Fr Sa Su
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
February/Sunday
February
Mo Tu We Th Fr Sa Su
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
First problem I see in your code, is: why are you using an while and a break just after start it?
It seems that you only need an if statement, not a while.
Second, you're using the same logic for any line of your calendar, that means: They start on Monday and end on Sunday.
You should change the start point of your inner for loop for your first line, depending on the day that it starts.
A simple dictionary can hold the number associated with each day of the week and for the first week you use it as the start point of the for instead of 1.
And your code will work only for Monday and Sunday as the first day of the month.
To make it works for any first day you should change the way you print spaces, changing it depending on the first day.
The code with the changes:
month = 'November'
day = 'Sunday'
x = 30
n = 1
days = { 'Mo': 1, 'Tu': 2, 'We': 3, 'Th': 4, 'Fr': 5, 'Sa': 6, 'Su': 7 }
print(" "*(days[day[:2]]-1), end='') # print 3 spaces for each day that isn't the first day of the month
start = days[day[:2]] # Set the start of the inner loop to the first day of the month
for i in range (1, 7):
for j in range (start, 8):
start = 1
if n < x+1:
print('%2s' % n, end=' ')
n = n + 1
print()

Categories