2014-12-10 2 views
1

В Python, у нас есть две даты:Количества раз, каждый будний день происходит между двумя датами

date_from = datetime.date(2014,02,8) 
date_to = datetime.date(2014,12,9) 

и нам нужно подсчитать, сколько раз каждый будний дня недели происходит между этими двумя днями. Каков хороший способ приблизиться к этому?

Например, если мы имеем:

date_from = datetime.date(2014,11,30) # Sunday 
date_to = datetime.date(2014,12,9) # Tuesday 

Ответ, который я ищу это (с днями недели либо в строке или цифровой форме) является:

'Sunday': 2 
'Monday': 2 
'Tuesday': 2 
'Wednesday': 1 
'Thursday': 1 
'Friday': 1 
'Saturday': 1 

ответ

3

Попробуйте это:

>>> from collections import Counter 
>>> weekdays = Counter() 

>>> date_from = datetime.date(2014,11,30) # Sunday 
>>> date_to = datetime.date(2014,12,9) # Tuesday 

>>> for i in range((date_to - date_from).days+1): 
... weekdays[(date_from + datetime.timedelta(i))\ 
...         .strftime('%a')] += 1 

>>> weekdays 
Counter({'Sun': 2, 'Tue': 2, 'Mon': 2, 'Wed': 1, 'Fri': 1, 
     'Thu': 1, 'Sat': 1}) 

Другой взятие:

def dates_between(start, end): 
    while start <= end: 
     yield start 
     start += datetime.timedelta(1) 

def count_weekday(start, end): 
    counter = Counter() 
    for date in dates_between(start, end): 
     counter[date.strftime('%a')] += 1 
    return counter 

Тогда:

>>> count_weekday(date_from, date_to) 
Counter({ 
    'Sun': 2, 
    'Tue': 2, 
    'Mon': 2, 
    'Wed': 1, 
    'Fri': 1, 
    'Thu': 1, 
    'Sat': 1 
}) 

[обновление]

Mark Ransom прокомментировал:

Нет необходимости рассчитывать каждый отдельный день отдельно. ... Я уже отдал предпочтение людям, которые делали это лучше.

Я уверен, что существует много других способов достижения такого же результата, но в чем смысл? Возможно, кто-то беспокоится о производительности. Я не - потому что:

  • разница между O(n) и O(n log n) не имеет никакого значения для малых п.
  • как сказал почтенный Дональд Кнут: «Преждевременная оптимизация - это корень всего зла».
  • Ответ на вопросы о производительности всегда «профиль его» - не раз я был удивлен тем, насколько неинтуитивными могут быть результаты.

И после профилирования, даже если другой алгоритм несколько миллисекунд быстрее:

  • является разница в производительности актуальна для применения?
  • - это код, о котором легче рассуждать?
  • Вы можете убедиться, что все угловые корпуса покрыты?

Торговля между сырым продуктом и более простым дизайном - это тот, который я готов взять большую часть времени.

+0

Нет необходимости рассчитывать каждый отдельный день отдельно. –

+0

@MarkRansom, даже если вы правы, ваш комментарий не очень конструктивен. Мне все равно, чтобы написать более эффективное решение - если да, напишите свой собственный ответ. :-) –

+0

Комментарий не предназначен для вас, это предназначалось для других, смотрящих на этот ответ. И мне не нужно писать самостоятельно, я уже отдал предпочтение людям, которые делали это лучше. –

1

Исправленного ответ:

Вычитание даты_ с даты_to, чтобы получить общее количество дней. Разделите на семь, чтобы получить количество недель - по одной из каждых дней в неделю за каждую неделю, очевидно. Затем добавьте в оставшихся будни:

>>> total_days = (date_to-date_from).days 
>>> total_days 
304 
>>> weeks = total_days/7 
>>> weeks 
43 
>>> days_of_week = {i:weeks for i in range (7)} 
>>> if date_to.weekday() > date_from.weekday(): 
... end_date = date_to.weekday() 
... else: 
... end_date = date_to.weekday() +7 
... 
>>> for i in range (date_from.weekday(), end_date + 1): 
... days_of_week[i %7] +=1 
... 
>>> days_of_week 
{0: 44, 1: 44, 2: 43, 3: 43, 4: 43, 5: 44, 6: 44} 
+0

Я считаю, что вопрос о подсчете количества раз каждый будний день происходит, а не общее количество дней. –

+0

Ну, я буду проклят, ты прав. –

+0

Исправлено это - извините за мозг пух. –

2

Для вас проблема, я буду использовать ответ @JonKiparsky. Он сказал что-то вам нужно:

>>> date_from = datetime.date(2014,02,8) 
>>> date_to = datetime.date(2014,12,9) 
>>> td = date_to - date_from 
>>> td.days 
304 
>>> 

Вам нужно просто использовать его рационально: в этой дельте у вас есть 304 дней, то есть 304/7 = 43 полных недель и 3 дня больше. Так первые 3 дня (date_from один и 2 больше) будет считаться 44, другие 43.

Это может быть проще, чем 2х2 !:

days = { 
    0: 0, 
    1: 0, 
    2: 0, 
    3: 0, 
    4: 0, 
    5: 0, 
    6: 0, 
} 
full_weeks = 304/7 # 43 
remainder = 304 % 7 # 3 
first_day = date_from.weekday() 
for day in days.keys(): 
    days[day] = full_weeks 
for i in range(0, remainder): 
    days[(first_day + i) % 7] += 1 
1

альтернативы без использования Counter бы:

days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 
     'Sunday'] 
day_counts = dict(zip(days, [0]*7)) 
this_day = date_from 
td = datetime.timedelta(days=1) 
while this_day <= date_to: 
    day_counts[days[this_day.weekday()]] += 1 
    this_day += td 

>>> day_counts 
{'Monday': 44, 'Tuesday': 44, 'Friday': 43, 'Wednesday': 43, 'Thursday': 43, 
'Sunday': 44, 'Saturday': 44} 
1

есть счетчик, который не отслеживает день недели, в один прекрасный день в то время, с начала до конца даты.

from datetime import datetime, timedelta 
from collections import Counter 

start=datetime(2014, 11, 30) 
until=datetime(2014, 12, 9) 
differences = [start + timedelta(i) for i in xrange((until - start).days + 1)] 
print dict(Counter(d.strftime('%A') for d in differences)) 

Выход:

{'Sunday': 2, 'Monday': 2, 'Tuesday': 2, 'Friday': 1, 'Wednesday': 1, 'Thursday': 1, 'Saturday': 1} 
+1

Это решение очень кратким, и я также рассматривал использование выражения генератора, но многие говорят, что вы не должны использовать выражение генератора или понимание списка только для побочных эффектов, потому что это может повредить разборчивость. Но для счетчиков это так заманчиво ... :-) –

Смежные вопросы