Аннотировать список месяцев с годом - PullRequest
3 голосов
/ 02 апреля 2020

У меня есть список нескольких последовательных месяцев, всегда включая текущий месяц. Например, когда я пишу это, это апрель 2020 года, поэтому допустимый список может быть любым из следующих:

example1 = ["January", "February", "March", "April", "May"]
example2 = ["December", "January", "February", "March", "April"]
example3 = ["April", "May", "June", "July", "August", "September", "October", "November", "December", "January", "February"]

Каков наилучший способ написать функцию Python, которая, учитывая список, подобный этому , вернет соответствующий список лет, поворачиваясь вокруг текущего месяца, являющегося текущим годом. Например:

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]

Лучшее, что я могу придумать, это разделить исходный список на текущий месяц, затем l oop в каждом направлении, сохраняя при этом отслеживание года, а затем поместить два результирующих списка все вместе. Но это слишком много петель. Есть ли более элегантное / быстрое решение?

Ответы [ 3 ]

2 голосов
/ 02 апреля 2020

Ну, как начинающий Python, я немного озадачился. Я думаю, что logi c будет:

  • найти индекс месяца, в котором вы работаете в настоящее время, например: April
  • установите его на текущий год
  • l oop через остальную часть списка, используя структуру if...elif... для генерации значений, согласно которым мы находимся в текущем месяце.

Я использовал from dateutil.relativedelta import relativedelta согласно этот старый пост на 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)]

Я уверен, что это можно сделать аккуратнее, но мне понравился вызов, так как я новичок в этом =)


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]

Все это было сделано с предположением, что текущий месяц, например, апрель, встречается только один раз в вашем списке (как по вашему объяснению). Даже тогда это будет работать до тех пор, пока мы можем с уверенностью предположить, что первый индекс апреля является вашей стартовой позицией.

Надеюсь, это поможет.

0 голосов
/ 02 апреля 2020

Сначала получите месяц как число, затем вы можете просмотреть список. Все месяцы до достижения цели будут в текущем или предыдущем году, тогда как месяцы после достижения цели будут в текущем или следующем году.

Функция name_to_num взята из этого ответа

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]


0 голосов
/ 02 апреля 2020

Вы можете сделать все в одном l oop

def solution(example):
    result = []
    month_index = example.index(datetime.now().strftime('%B')) + 1
    current_year = datetime.now().year
    month_number = datetime.now().month

    for _ in example:
        if month_index > month_number:
            result.append(current_year - 1)
        elif month_index <= month_number < 12 + month_index:
            result.append(current_year)
        else:
            result.append(current_year + 1)
        month_number += 1

    return result
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...