Reputation: 1308
I have a list of several consecutive months, always including the current month. For example, as I write this it is April 2020, so a valid list could be any of the following:
example1 = ["January", "February", "March", "April", "May"]
example2 = ["December", "January", "February", "March", "April"]
example3 = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"]
What's the best way to write a Python function which, given a list like this, would return a corresponding list of years, pivoting around the current month being the current year. For example:
f(example1) = [2020, 2020, 2020, 2020, 2020]
f(example2) = [2019, 2020, 2020, 2020, 2020]
f(example3) = [2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2021, 2021]
The best I can think of is partition the original list by the current month, then loop in each direction while also keeping track of the year, then put the two resulting lists together. But this is way too much looping. Is there a more elegant / faster solution?
Upvotes: 3
Views: 510
Reputation: 75870
Well, as a Python beginner I have been puzzling a little bit. I think the logic would be:
if...elif...
structure to generate values according to which side of the current month we are.I made use of from dateutil.relativedelta import relativedelta
as per this older post on SO.
import datetime as dt
from dateutil.relativedelta import relativedelta
def get_years_for(months):
today = dt.date.today()
try:
month_index = months.index(today.strftime("%B"))
except ValueError:
return []
current_month = today.month
current_year = today.year
day1 = dt.date(current_year, current_month, 1)
years = {month_index: current_year}
for idx, month in enumerate(months):
if idx < month_index:
years[idx] = (day1 - relativedelta(months=month_index - idx)).year
elif idx > month_index:
years[idx] = (day1 + relativedelta(months=idx - month_index)).year
return [years[i] for i in sorted(years)]
I'm sure this can be done neater, but I liked the challenge as I'm new to this =)
example1 = ["January", "February", "March", "April", "May"]
[2020, 2020, 2020, 2020, 2020]
example2 = ["December", "January", "February", "March", "April"]
[2019, 2020, 2020, 2020, 2020]
example3 = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"]
[2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2021, 2021]
example4 = ["November", "December", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"]
[2019, 2019, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2021, 2021]
All this has been done with the assumption the current month, e.g. April, only occurs once in your list (as per your explanation). Even then, it will still work as long as we can safely make the assumption that the first index of April is your starting position.
Hope it helps.
Upvotes: 2
Reputation: 320
First get the month as a number, then you can iterrate over the list. All months before the target will be in the current or previous year while the months after the target will be in the current or next year.
The name_to_num
function came from this answer
from datetime import datetime
import calendar
name_to_num = {name: num for num, name in enumerate(calendar.month_name) if num}
def f(months):
curr_month = datetime.now().strftime("%B") # Get month name.
curr_year = datetime.now().year
curr_month_idx = name_to_num[curr_month]
years = []
seen_curr_month = False
for month in months:
month_idx = name_to_num[month]
# Set seen to True once the terget month is reached.
if month_idx == curr_month_idx:
seen_curr_month = True
# Target has not been seen
if not seen_curr_month:
# But the months are grater than target then its the previous year.
if month_idx > curr_month_idx:
years.append(curr_year-1)
# If they are smaller or equal to target then its the current year.
else:
years.append(curr_year)
# All years from now on will be greater or equal to current.
else:
# If the month is greater than current its the same year.
if month_idx >= curr_month_idx:
years.append(curr_year)
# Otherwise its the next year.
else:
years.append(curr_year+1)
return years
example1 = ["January", "February", "March", "April", "May"]
example2 = ["December", "January", "February", "March", "April"]
example3 = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"]
print(f(example1)) # [2020, 2020, 2020, 2020, 2020]
print(f(example2)) # [2019, 2020, 2020, 2020, 2020]
print(f(example3)) # [2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2021, 2021]
Upvotes: 0