Why doesn't this project euler #19 code work? (Python) - python

I made a code for project euler's #19 problem in Python, and it doesn't give me the right answer.
The question is: You are given the following information, but you may prefer to do some research for yourself.
1 Jan 1900 was a Monday.
Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
What is the problem here?:
months = {'January': 31,
'February': 28,
'March': 31,
'April': 30,
'May': 31,
'June': 30,
'July': 31,
'August': 31,
'September': 30,
'November': 30,
'December': 31
}
years = range(1900, 2001)
day = 1
def main():
global day
for year in years:
if year % 4 == 0 or year % 400 == 0:
months['February'] = 29
else:
months['February'] = 28
for month in months:
if months[month] == 31:
day += 31 % 7 +1
while day > 7:
day = day - 7
if day == 1:
yield day
result = sum(main())
print (result)
Also it generates different answers everytime I use,
Thanks :)

I don't understand the algorithm and your code. But I can say about this.
it generates different answers everytime I use
Probably you forgot to initialize month, year and day before executing result = sum(main()).

The solution will be simpler, if you use dateutil library:
In [16]: from datetime import datetime
In [17]: from dateutil.relativedelta import relativedelta
In [18]: current = datetime(1901, 1, 1)
In [19]: end = datetime(2001, 1, 1)
In [20]: ans = 0
In [21]: while current < end:
....: if current.weekday() == 6:
....: ans += 1
....: current += relativedelta(months=1)
....:
In [22]: ans
Out[22]: 171

Related

simple day converter? getting how many weeks and days are in a number python

rewritten....
Im trying to get the number of weeks, and how many days extra, out of a number.
for example..
if the program has been running for 5 days, it will say week 1 day 5
if the program has been running for 14 days, it will say week 2 day 7
if the program has been running for 16 days, it will say week 3 day 2
I didnt upload my original code becuase as I was writing this question, i solved the HUGE mess i had, and didnt want to post a bunch of useless code. but still wanted to share my solution becuase I couldn't find another answer.
this code is what I got to work, but the answer to this question if a simplified version discovered after comments helped me understand a bit better.
import math
totaldays = 77
week = totaldays / 7
if week <= 1:
week, day = 1, totaldays % 7
if day == 0:
day = 7
elif week >=1:
week, day = math.ceil(week), totaldays % 7
days = [1, 2, 3, 4, 5, 6, 7]
if day not in days:
day = 7
print("Total days: " + str(totaldays) + " (week: " + str(int(week)) + ", day: " + str(int(day)) + ")")
with help from #samwise i shortened the hell out of this.
import math
totaldays = 5
day = totaldays % 7
days = [1, 2, 3, 4, 5, 6, 7]
if day not in days:
day = 7
print(f"Total days: {totaldays} (week: {math.ceil(totaldays / 7)}, day: {day})")
Further improving:
import math
totaldays = 7
day = totaldays % 7
if day == 0:
day = 7
print(f"Total days: {totaldays} (week: {math.ceil(totaldays / 7)}, day: {day})")

Write a python program that gives me every year from 1583 to 2017 where new year is a Monday and x-mas (24.12) is not

I want to write a python program that gives me every year from 1583 to 2017 where new years day (1.1.) is a Monday and X-mas (24.12) is not. I want to do it with the use of datetime.
I have already tried something but as I am new to python and do not know the datetime module very well, i did not come up with a solution
import calendar
def is_ny_monday_while_xmas_not(date,weekday):
if (calendar.weekday(date.year, date.month, 1) == "Monday":
the output should look like :
1684
1846
1934
...
(I do not know the right years so this is just an example)
It's pretty straitforward
from datetime import date
for year in range(1583, 2018):
if date(year, 1, 1).weekday() == 0 and date(year, 12, 24).weekday() != 0:
print(year)
Mention the end of range, which I've changed from 2017 to 2018 to because 'stop' not included in enumeration (but it isn't changed anything cause it's not Monday).
Good optimization from another answer (mention 4 as the third parameter to range()) but beware to copypaste it into another check conditions.
from datetime import date
for year in range(1584, 2018, 4):
if date(year, 1, 1).weekday() == 0 and date(year, 12, 24).weekday() != 0:
print(year)
Firstly, there are 357 days between 1 Jan and 24 Dec on a year that isn't a leap year, and 357 is divisible by 7. This means that if January 1 is a Monday, December 24 also is. Therefore, the question is equivalent to: what years are leap years and also start with a Monday?
from datetime import date
year = 1584 #first leap year after 1583
while year < 2017:
if date(year, 1, 1).weekday() == 0:
if year % 100 != 0 or year % 400 == 0 #years that are divisible by 100 aren't leap years, unless divisible by 400.
print(year)
year += 4
This should print out all years you need.

In python convert day of year to month and fortnight

I want to convert day (say 88) and year (say 2004) into its constituent month and nearest number out of 2 possibilities:
If the day of month ranges from 1 to 14, then return 1, else return 15
I am doing this:
datetime.datetime(year, 1, 1) + datetime.timedelta(days - 1)
However, this is only part of the way to the soln. The end result for day 88 and year 2004 should be:
March 15 (Month is March and closest day is 15th march).
-- EDIT: Changed question to reflect that I mean day of year and not julian day
You can use the replace method:
In [11]: d
Out[11]: datetime.datetime(2004, 3, 28, 0, 0)
In [12]: d.replace(day=1 if d.day < 15 else 15)
Out[12]: datetime.datetime(2004, 3, 15, 0, 0)
In [13]: t = pd.Timestamp(d)
In [14]: t.replace(day=1 if t.day < 15 else 15)
Out[14]: Timestamp('2004-03-15 00:00:00')
The reason this returns a new datetime rather than updating is because datetime objects are immutable (they are can't be updated).
Note: there's a format for that day of the month:
In [21]: datetime.datetime.strptime("2004+88", "%Y+%j")
Out[21]: datetime.datetime(2004, 3, 28, 0, 0)
In [22]: pd.to_datetime("2004+88", format="%Y+%j")
Out[22]: Timestamp('2004-03-28 00:00:00')
Something like this?
year = 2015
day = 88
d = dt.datetime(year, 1, 1) + dt.timedelta(88 - 1)
>>> d.month, 1 if d.day < 15 else 15
(3, 15)
It would be easy to convert the tuple pair into something useful depending on your requirements.
For example
dt.datetime(year, d.month, 1 if d.day < 15 else 15).strftime('%Y-%b-%d')
'2015-Mar-15'
However, you have not specified the type of data you are expecting (datetime.date, pd.Timestamp, string, etc.)
How about something like..
tmp_date = datetime.datetime(year, 1, 1) + datetime.timedelta(days - 1)
rday = 1 if tmp_date.day < 15 else 15
result = datetime.datetime(tmp_date.year, tmp_date.month, rday)

Project Euler #19, Python

I was solving Project Euler #19:
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
And here is the code :
months = { "January": 31,
"February" : 28,
"March" : 31,
"April" : 30,
"May" : 31,
"June" : 30,
"July" : 31,
"August" : 31,
"September" : 30,
"October" : 31,
"November" : 30,
"December" : 31}
def countingSundays():
day = 1
sunday_count = 0
for year in xrange(1901,2001):
for m in months:
day += months[m]
if year % 4 == 0 and m == "February":
day += 1
if day % 7 == 0:
sunday_count += 1
print "Sundays:", sunday_count
The output of the program is 172 which is incorrect.
I searched the answer to be 171.
So I wanted to know why am I getting the extra 1 Sunday ?
You're iterating over the months dict, expecting it to iterate in the order of the months, but dicts aren't ordered, so you can get the months in the wrong order.
Since you don't actually need the month names, you can just make months a list of the month lengths instead.
You should use the datetime library, which will handled all the leap year information automatically:
from datetime import date
from collections import Counter
counter = Counter()
for year in xrange(1901, 2001):
for month in xrange(1, 13):
day = date(year, month, 1)
counter[day.weekday()] += 1
print counter[6]
import time
from math import floor
"""
Gaussian algorithm to determine day of week
"""
def day_of_week(year, month, day):
"""
w = (d+floor(2.6*m-0.2)+y+floor(y/4)+floor(c/4)-2*c) mod 7
Y = year - 1 for January or February
Y = year for other months
d = day (1 to 31)
m = shifted month (March = 1, February = 12)
y = last two digits of Y
c = first two digits of Y
w = day of week (Sunday = 0, Saturday = 6)
"""
d = day
m = (month - 3) % 12 + 1
if m > 10: Y = year - 1
else: Y = year
y = Y % 100
c = (Y - (Y % 100)) / 100
w = (d + floor(2.6 * m - 0.2) + y + floor(y/4) + floor(c/4) - 2*c) % 7
return int(w)
"""
Compute the number of months starting on a given day of the week in a century
"""
def months_start_range(day,year_start,year_end):
total = 0
for year in range(year_start, year_end + 1):
for month in range(1,13):
if day_of_week(year, month, 1) == day: total += 1
return total
start = time.time()
total = months_start_range(0,1901,2000)
elapsed = time.time() - start
print("%s found in %s seconds") % (total,elapsed)
This might you solve the problem.
It took around 0.068 seconds to solve it.
Here is a different approach to tackle this question
public static void main(String[] args) {
int k = 0;
// String months[] = { "January", "February", "March", "April", "May", "June",
// "July", "August", "September",
// "October", "November", "December" };
String Days[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
int MonthsDdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int counter = 0;
for (int t = 1900; t <= 2000; t++) {
MonthsDdays[1]=28;
if (t % 4 == 0) {
if (t % 100 == 0)
{
if (t % 400 == 0)
MonthsDdays[1] = 29;
} else if (t % 100 != 0)
MonthsDdays[1] = 29;
}
int p = 0;
while (p < 12) {
for (int j = 0; j < MonthsDdays[p]; k++, j++) {
if (k == 7)
k = 0;
if (Days[k].equalsIgnoreCase("Sunday") && j == 0 && t > 1900) {
counter++;
}
}
p++;
}
}
System.out.println(counter);
}
I tried the Mathematical approach although we could use the calendar functions.
I first calculated the math of the months to determine the relationships between the first dates of the months using the other months. Also, for simplicity in calculating leap years, I calculated the year from March to Feb. If you want to calculate for the Jan and Feb of 1901, you can write a separate condition, and do the same to remove Jan and Feb of 2001. However, in this case, they do not really matter as they are not Sundays, so you could remove the last if condition for this specific case.
# Zero is Sunday and the rest of the days are according to mod7
# li stores the first days of the months in the year in every iteration
# The year in initial li is 1900 but the contents are Mar-1900 to Feb-1901
# At the end, we can check if Jan or Feb of 2001 contain a Sunday and remove if it does
li, cnt = [4,0,2,5,0,3,6,1,4,6,2,5], 0
# Could also initialize li from by the same method as below, but I had already calculated those
# cnt adds number of zeros in every iteration (the number of Sundays in every year) to its value
# As we don't count for the year 1900 cnt=0, else initialize cnt=li.count(0)
for year in range(1901,2001):
if year%4==0:
li[0]=li[8]=(li[11]+1)%7 #Set March and November to +1 value than last Feb
else:
li[0]=li[8]=li[11] #Set March and November to same value as last Feb
# The following values of other months will depend solely on their own March value
# You can check the Math if you want to
li[3]=li[11]=(li[0]+1)%7;li[6]=li[9]=(li[0]+2)%7;li[1]=li[4]=(li[0]+3)%7;li[2]=li[10]=(li[0]-2)%7;li[5]=(li[0]-1)%7;li[7]=(li[0]-3)%7
cnt = cnt + li.count(0)
# This is to remove the extra two months of the year 2001 if they bother the answer
if li[10] == 0 or li[11] == 0:
cnt = cnt-1
print(cnt)
This was my first answer on StackOverflow, I hope I wrote well. ;-)
The mistakes you have:
The way you calculate leap years
Dictionary does not keep the order necessarily
You assume January 1st is Sunday
The correct program would be:
from collections import OrderedDict
months = OrderedDict( [("January",31),("February", 28),("March",31),
("April", 30), ("May", 31), ("June", 30),
("July", 31), ("August", 31), ("September", 30),
("October", 31), ("November", 30), ("December", 31)] )
days = ['Tuesday','Wednesday', 'Thursday','Friday','Saturday', 'Sunday', 'Monday']
day = 0
sunday_count = 0
def isLeap(year): #https://en.wikipedia.org/wiki/Leap_year#Algorithm
leap = True
if year % 4 != 0:
leap = False
elif year % 100 != 0:
leap = True
elif year % 400 != 0:
leap = False
return leap
for year in xrange(1901,2001):
leap = isLeap(year)
for m in months:
dayName = days[day%7]
if dayName == "Sunday":
sunday_count += 1
#print year, m, dayName
day += months[m]
if leap == True and m == "February":
day += 1
print sunday_count
# print 171
Also, some days:
1901 January Tuesday
1901 February Friday
1901 March Friday
1901 April Monday
1901 May Wednesday
1901 June Saturday
1901 July Monday
1901 August Thursday
1901 September Sunday
...
import pandas as pd
from datetime import date
start = date(1901, 1, 1)
end = date(2000, 12, 31)
d = pd.date_range(start, end, freq='MS').strftime('%A')
s = pd.Series(d)
print(s.value_counts())
So I approached this problem from not a date perspective but of a counting days.
Here's my solution:.
days_1st = list()
day_counter = 1
for year in range(1900, 2001):
for month in range(1,13):
#Skip for year 1900 as count starts from 1901, but this still
#adds the days hence keeping the cycle in sync!
if year != 1900:
days_1st.append(day_counter)
if month == 4 or month == 6 or month == 9 or month == 11:
day_counter+=30
elif month == 2 and ((year % 100 == 0 and year % 400 == 0) or (year % 100 != 0 and year % 4 == 0)):
day_counter+=29
elif month == 2:
day_counter+=28
else:
day_counter+=31
# mod 7 because since the day the counting started (1 Jan 1900 -
# Monday) Every 7th day is a sunday!
days_sunday = list(filter(lambda x: x % 7 == 0, days_1st))
print(len(days_sunday))
A = [31,28,31,30,31,30,31,31,30,31,30,31]
sunday =0
gK = 1
for y in range(1901,2001):
if(y %4 ==0):
A[1] = 29
else:
A[1] = 28
for m in range(len(A)):
for d in range(1,A[m]+1):
if(gK ==6):
if(d==1):
sunday +=1
gK =0
else:
gK =gK+1
print(sunday)
==>Solution in python
euler19.py
normal_year = [31,28,31,30,31,30,31,31,30,31,30,31]
leap_year = [31,29,31,30,31,30,31,31,30,31,30,31]
years = [ normal_year ] * 100
for i in range(3, len(years), 4) :
years[i] = leap_year
current_day = (0+365) % 7
sundays = 0
for y in years :
for m in y :
if current_day % 7 == 6:
sundays += 1
current_day += m%7
print (sundays)
I think I got the answer. I am not sure though.. your logic was right. But needed a little improvement. We need to start off by counting the number of Tuesdays first as we clearly know that it was Monday on Jan 1, 1900.
months = { "January": 31,
"February" : 28,
"March" : 31,
"April" : 30,
"May" : 31,
"June" : 30,
"July" : 31,
"August" : 31,
"September" : 30,
"October" : 31,
"November" : 30,
"December" : 31}
for month in months:
print(months[month])
tuesday_count = 0
day = 0
extra_days = 0
for year in range(1901, 2001):
days_in_the_year = 0
for month in months:
day += months[month]
days_in_the_year += months[month]
if( year % 4 == 0 and month == 'February'):
if (year % 100 != 0):
extra_days += 1
days_in_the_year += 1
day += 1
elif(year % 100 ==0 and year % 400 ==0):
extra_days += 1
days_in_the_year += 1
day += 1
if( (day) % 7 == 0):
tuesday_count += 1
print('No. of days in the year',year,'are',days_in_the_year)
print('No. of Tuesdays counted so far is =', tuesday_count)
print('The number of extra_days because of the leap years are:',extra_days)
# print('extra_days % 7 =', '25 % 7 =', extra_days % 7)
print('So, there were', extra_days // 7, 'extra_no_of_weeks left that we haven\'t considered. After that, it\'s followed by --wed, thu, fri and sat (we don\'t need to consider that).\n So, the total number of Tuesdays are', tuesday_count+3 )
tuesday_count += 3
print('This means only 2 Sundays that have followed')
sunday_count = tuesday_count - 1
print('Since, 1901 Jan1 would be a Tuesday, we need to subract one from the total number of Sundays\n So, the total number of sundays are:', )
sunday_count=sunday_count-1
print(sunday_count)
months=[31,28,31,30,31,30,31,31,30,31,30,31]
leap=[31,29,31,30,31,30,31,31,30,31,30,31]
sundays=0
start=2
for y in range(25):
for nonleap in range (3):
for j in months:
start=(start+j)%7
if start == 0:
sundays+=1
for m in leap:
start=(start+m)%7
if start == 0:
sundays+=1
print sundays
Note that the problem defines the first day of 1900 as Monday and you define the first day of 1901 as Monday.
months = [31,28,31,30,31,30,31,31,30,31,30,31]
def countingSundays():
day = 1
sunday_count = 0
for year in range(1900,1901):
for m in months:
day += m
if (year % 4 == 0 and m == 28):
day += 1
for year in range(1901,2001):
for m in months:
day += m
if (year % 4 == 0 and m == 28):
day += 1
if day % 7 == 0:
sunday_count += 1
return sunday_count
print ("Sundays:", countingSundays())
you have initialized the day variable to 1 but the 1st Jan 1901 is a Tuesday. I made the same error ;-)

python days until specified date without date library

MONTHLEN = [ 0, # No month zero
31, # 1. January
28, # 2. February (ignoring leap years)
31, # 3. March
30, # 4. April
31, # 5. May
30, # 6. June
31, # 7. July
31, # 8. August
30, # 9. September
31, #10. October
30, #11. November
31, #12. December
]
def count_normal_year(year, start_month, start_date, end_month, end_date):
day_count=0
if start_month == end_month and start_date==end_date:
print(0)
else:
day_count+=(MONTHLEN[start_month]-start_date)
next_start_month_index=start_month + 1
for months in range(MONTHLEN[next_start_month_index, MONTHLEN[end_month]):
day_count+=MONTHLEN[months]
day_count +=end_date
print(day_count)
I'm not allowed to use the date library.
my idea for this loop is to subtract the days left in the starting month, and then loop through MONTHLEN starting at MONTHLEN index of the next starting month up until the end month.
IE 1 2 12 1
it would give 29 then start February first and add the total days of all months up until December (but not including December) then add the end date
so 28 +31 +30+31+30+31+31+30+31+30 for adding the total days in the month to get me to December then add the end date of 1
I'm not sure the correct syntax to code my idea

Categories