Skip to main content
Code Review

Return to Answer

Add tests.
Source Link
Peilonrayz
  • 44.4k
  • 7
  • 80
  • 157
import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 today = (now.weekday(), now.hour, now.minute)
 for lecture in LECTURES:
 if today < lecture:
 return lecture
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, now.replace(hour=hour, minute=minute, second=0, microsecond=0)
 + datetime.timedelta(day - now.weekday())
 )

Test code

def replace(date, changes):
 day, hour, minute = changes
 return date.replace(hour=hour, minute=minute) + datetime.timedelta(days=day)
def test(tests, bases, fn):
 for base in bases:
 date = base.replace(second=0, microsecond=0) - datetime.timedelta(days=base.weekday())
 for test, exp in tests:
 try:
 output = fn(replace(date, test))
 except Exception as e:
 print(f'❌ {test=}, {exp=}')
 print(' ', e)
 continue
 expected = replace(date, exp)
 try:
 assert output == expected
 except AssertionError:
 print(f'❌ {test=}, {exp=}')
 print(' ', date, output, expected)
 else:
 print(f'✔️ {test=}, {exp=}')
TESTS = [
 [(0, 0, 0), (0, 10, 15)],
 [(0, 10, 10), (0, 10, 15)],
 [(0, 10, 15), (2, 12, 15)],
 [(0, 10, 20), (2, 12, 15)],
 [(1, 12, 20), (2, 12, 15)],
 [(1, 13, 20), (2, 12, 15)],
 [(2, 10, 0), (2, 12, 15)],
 [(2, 10, 14), (2, 12, 15)],
 [(2, 12, 15), (3, 8, 15)],
 [(3, 8, 15), (7, 10, 15)],
]
BASES = [
 datetime.datetime.now(),
 datetime.datetime(2020, 9, 1),
 datetime.datetime(2020, 10, 1) - datetime.timedelta(days=1),
 datetime.datetime(2020, 12, 1),
 datetime.datetime(2021, 1, 1) - datetime.timedelta(days=1),
]
test(TESTS, BASES, get_next_lecture)
import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 today = (now.weekday(), now.hour, now.minute)
 for lecture in LECTURES:
 if today < lecture:
 return lecture
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)
import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 today = (now.weekday(), now.hour, now.minute)
 for lecture in LECTURES:
 if today < lecture:
 return lecture
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return ( now.replace(hour=hour, minute=minute, second=0, microsecond=0)
 + datetime.timedelta(day - now.weekday())
 )

Test code

def replace(date, changes):
 day, hour, minute = changes
 return date.replace(hour=hour, minute=minute) + datetime.timedelta(days=day)
def test(tests, bases, fn):
 for base in bases:
 date = base.replace(second=0, microsecond=0) - datetime.timedelta(days=base.weekday())
 for test, exp in tests:
 try:
 output = fn(replace(date, test))
 except Exception as e:
 print(f'❌ {test=}, {exp=}')
 print(' ', e)
 continue
 expected = replace(date, exp)
 try:
 assert output == expected
 except AssertionError:
 print(f'❌ {test=}, {exp=}')
 print(' ', date, output, expected)
 else:
 print(f'✔️ {test=}, {exp=}')
TESTS = [
 [(0, 0, 0), (0, 10, 15)],
 [(0, 10, 10), (0, 10, 15)],
 [(0, 10, 15), (2, 12, 15)],
 [(0, 10, 20), (2, 12, 15)],
 [(1, 12, 20), (2, 12, 15)],
 [(1, 13, 20), (2, 12, 15)],
 [(2, 10, 0), (2, 12, 15)],
 [(2, 10, 14), (2, 12, 15)],
 [(2, 12, 15), (3, 8, 15)],
 [(3, 8, 15), (7, 10, 15)],
]
BASES = [
 datetime.datetime.now(),
 datetime.datetime(2020, 9, 1),
 datetime.datetime(2020, 10, 1) - datetime.timedelta(days=1),
 datetime.datetime(2020, 12, 1),
 datetime.datetime(2021, 1, 1) - datetime.timedelta(days=1),
]
test(TESTS, BASES, get_next_lecture)
Fix the issue
Source Link
Peilonrayz
  • 44.4k
  • 7
  • 80
  • 157

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 today if= (now.weekday() <= day
 and, now.hour <=, hournow.minute)
 for lecture in andLECTURES:
 now.minute < minute
 if today < )lecture:
 return day, hour, minutelecture
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 today if= (now.weekday() <= day
 and, now.hour <=, hournow.minute)
 for lecture in andLECTURES:
 now.minute < minute
 if today < )lecture:
 return day, hour, minutelecture
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
  if (now.weekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
  if (now.weekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 today = (now.weekday(), now.hour, now.minute)
 for lecture in LECTURES:
 if today < lecture:
 return lecture
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 today = (now.weekday(), now.hour, now.minute)
 for lecture in LECTURES:
 if today < lecture:
 return lecture
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

added 12 characters in body
Source Link
Peilonrayz
  • 44.4k
  • 7
  • 80
  • 157

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.dayweekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
def get_next_lecture(nownow=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.dayweekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.day <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
def get_next_lecture(now):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.day <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

Your algorithm seems good, but the while loop, and lecture_hour and lecture_minute variables make your code a lot more complicated.

If we KISS then a simple algorithm is to just remove () from Lectures and iterate through it, since it is sorted. The first lecture that is after the current time is the lecture we want.

This is nice and simple:

import datetime
LECTURES = [(0, 10, 15), (2, 12, 15), (3, 8, 15)]
def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.weekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
def get_next_lecture(now=None):
 if now is None:
 now = datetime.datetime.now()
 day, hour, minute = _get_next_lecture(now)
 return now.replace(day=now.day + day, hour=hour, minute=minute, second=0, microsecond=0)

From here we can see if the weekday is 4-6 then _get_next_lecture will return nothing and so will error.

This is easy to solve, we just return the first lecture with +7 days.

def _get_next_lecture(now):
 for day, hour, minute in LECTURES:
 if (now.weekday() <= day
 and now.hour <= hour
 and now.minute < minute
 ):
 return day, hour, minute
 day, hour, minute = LECTURES[0]
 return day + 7, hour, minute

With only 3 lectures there's not much point in optimizing further. However if you have more, here is some food for thought:

  • You can use bisect to find where to insert into in \$O(\log n)\$ time.

  • You can change LECTURES into a 7 item list with the weekday as the index and the lectures as the value (always as a list). From here you just find the date using either of the above algorithms.

    This would look like your Lectures. But with a list for each day.

    This has either \$O(d)\$ or \$O(\log d)\$ time where \$d\$ is the maximum amount of lectures in a day.

Remove those pesky brackets
Source Link
Peilonrayz
  • 44.4k
  • 7
  • 80
  • 157
Loading
Source Link
Peilonrayz
  • 44.4k
  • 7
  • 80
  • 157
Loading
lang-py

AltStyle によって変換されたページ (->オリジナル) /