2015-07-22 12 views
7

Si consideri il seguente elenco di giorno della settimana ore coppie in 24H formato:conteggio coppie giorno della settimana ore tra due date

{ 
'Mon': [9,23], 
'Thu': [12, 13, 14], 
'Tue': [11, 12, 14], 
'Wed': [11, 12, 13, 14] 
'Fri': [13], 
'Sat': [], 
'Sun': [], 
} 

e due punti di tempo, ad esempio:

  • Inizio:

    datetime.datetime(2015, 7, 22, 17, 58, 54, 746784) 
    
  • Fine:

    datetime.datetime(2015, 8, 30, 10, 22, 36, 363912) 
    

dire che abbiamo bisogno di sapere quante ore ci sono tra questi due datetimes (sia arrotondamento verso l'alto o verso il basso) per ciascuna delle giorno della settimana ore coppie specificate sopra.

Come posso affrontare questo problema in Python? Ho esplorato timedelta e relativedelta in un livello generale di dettaglio, ma non ho trovato nulla che fornisca qualcosa di simile a questo.

Per semplicità, possiamo supporre che tutto si riferisca allo stesso fuso orario.


Forse un problema più semplice è concentrarsi su una singola coppia di ore del giorno, ad es. Quanti Wednesdays: 14 ci sono tra due datari arbitrari?

+0

Does fuso orario importa qui? –

+0

Grazie a @SimeonVisser Possiamo supporre che tutto si riferisca allo stesso fuso orario. Farò chiarezza nel PO. –

+0

Quindi, in pratica, quanti mercoledì 14:00 sono lì tra 2015-07-22 17:58:54 e 2015-08-30 10:22:36? – TigerhawkT3

risposta

4

Forse qualcosa di simile:

from calendar import day_abbr 
from datetime import datetime, timedelta 


def solve(start, end, data): 
    days = list(day_abbr) 
    output = dict.fromkeys(days, 0) 

    while start <= end: 
     day = days[start.weekday()] 
     if start.hour in data[day]: 
      output[day] += 1 
     start = start + timedelta(minutes=60) 

    return output 


data = { 
'Mon': [9, 23], 
'Thu': [12, 13, 14], 
'Tue': [11, 12, 14], 
'Wed': [11, 12, 13, 14], 
'Fri': [13], 
'Sat': [], 
'Sun': [], 
} 

start = datetime(2015, 7, 22, 17, 58, 54, 746784) 
end = datetime(2015, 8, 30, 10, 22, 36, 363912) 

print solve(start, end, data) 
# {'Wed': 20, 'Sun': 0, 'Fri': 6, 'Tue': 15, 'Mon': 10, 'Thu': 18, 'Sat': 0} 

Ottenere conteggio per ogni giorno ora:

from calendar import day_abbr 
from collections import defaultdict 
from datetime import datetime, timedelta 
from pprint import pprint 


def solve(start, end, data): 
    days = list(day_abbr) 
    output = defaultdict(lambda: defaultdict(int)) 

    while start <= end: 
     day = days[start.weekday()] 
     if start.hour in data[day]: 
      output[day][start.hour] += 1 
     start = start + timedelta(minutes=60) 
    return {k: dict(v) for k, v in output.items()} 


data = { 
'Mon': [9, 23], 
'Thu': [12, 13, 14], 
'Tue': [11, 12, 14], 
'Wed': [11, 12, 13, 14], 
'Fri': [13], 
'Sat': [], 
'Sun': [], 
} 

start = datetime(2015, 7, 22, 17, 58, 54, 746784) 
end = datetime(2015, 8, 30, 10, 22, 36, 363912) 

pprint(solve(start, end, data)) 
# output 
{'Fri': {13: 6}, 
'Mon': {9: 5, 23: 5}, 
'Thu': {12: 6, 13: 6, 14: 6}, 
'Tue': {11: 5, 12: 5, 14: 5}, 
'Wed': {11: 5, 12: 5, 13: 5, 14: 5}} 
0

Quindi, se comprendo correttamente la tua domanda, inizierei a trovare la prima occorrenza dell '"ora" nell'intervallo di tempo e quindi a cercare le prossime occorrenze settimana per settimana. Come questo:

#!/usr/bin/python 
from __future__ import print_function 
import datetime 
import dateutil.relativedelta 


def hours_between(start, end, weekday, hour): 
    first = start + dateutil.relativedelta.relativedelta(
     weekday=weekday, hour=hour, 
     minute=0, second=0, microsecond=0) 
    week = dateutil.relativedelta.relativedelta(weeks=1) 

    all_dates = [] 
    d = first 
    while d < end: 
     all_dates.append(d) 
     d += week 

    return all_dates 


def main(): 
    start = datetime.datetime(2015, 7, 22, 17, 58, 54, 746784) 
    end = datetime.datetime(2015, 8, 30, 10, 22, 36, 363912) 
    all_dates = hours_between(start, end, dateutil.relativedelta.WE, 14) 
    print(all_dates) 
    print(len(all_dates)) 

main() 
2

Forse non afferro il problema completamente, ma si potrebbe ottenere tutte le ore tra le due date e riassumere quante volte ogni ora e il giorno appare tra le due date:

from datetime import datetime 
from dateutil import rrule,parser 


d={ 
'Mon': [9, 23], 
'Thu': [12, 13, 14], 
'Tue': [11, 12, 14], 
'Wed': [11, 12, 13, 14], 
'Fri': [13], 
'Sat': [], 
'Sun': [], 
} 

st = datetime(2015, 7, 22, 17, 58, 54, 746784) 

ed = datetime(2015, 8, 30, 10, 22, 36, 363912) 
dates = list(rrule.rrule(rrule.HOURLY, 
         dtstart=parser.parse(st.strftime("%Y-%m-%d %H:%M:%S")), 
         until=parser.parse(ed.strftime("%Y-%m-%d %H:%M:%S")))) 


days = {"Mon":0,"Tue": 1,"Wed":2,"Thu": 3,"Fri":4,"Sat":5,"Sun":6} 

for k, val in d.items(): 
    for v in val: 
     print("day: {} hour: {}".format(k,v)) 
     day = days[k] 
     print(sum((v == dt.hour and dt.weekday() == day) for dt in dates)) 

uscita:

day: Wed hour: 11 
5 
day: Wed hour: 12 
5 
day: Wed hour: 13 
5 
day: Wed hour: 14 
5 
day: Fri hour: 13 
6 
day: Tue hour: 11 
5 
day: Tue hour: 12 
5 
day: Tue hour: 14 
5 
day: Mon hour: 9 
6 
day: Mon hour: 23 
5 
day: Thu hour: 12 
5 
day: Thu hour: 13 
5 
day: Thu hour: 14 
5 

Non sono sicuro se si desidera che la somma per tutte le ore in ciascuna lista o totale per ogni singola ora, ma in entrambi i casi è possibile memorizzare l'output in un dict.

counts = {'Thu':{}, 'Sun':{}, 'Fri':{}, 'Mon':{}, 'Tue':{}, 'Sat':{}, 'Wed':{}} 
for k, val in d.items(): 
    for v in val: 
     day = days[k] 
     sm = sum((v == dt.hour and dt.weekday() == day) for dt in dates) 
     counts[k][v] = sm 

from pprint import pprint as pp 
pp(counts) 

uscita:

{'Fri': {13: 6}, 
'Mon': {9: 5, 23: 5}, 
'Sat': {}, 
'Sun': {}, 
'Thu': {12: 6, 13: 6, 14: 6}, 
'Tue': {11: 5, 12: 5, 14: 5}, 
'Wed': {11: 5, 12: 5, 13: 5, 14: 5}} 
2

Ecco una soluzione con i loop e datetime :

import datetime 

pairs = {1: [9,23], 
2: [11, 12, 14], 
3: [11, 12, 13, 14], 
4: [12, 13, 14], 
5: [13], 
6: [], 
7: [] 
} 

start = datetime.datetime(2015, 7, 22, 17, 58, 54, 746784) 
end = datetime.datetime(2015, 8, 30, 10, 22, 36, 363912) 
result={} 
for d,hl in pairs.items(): 
    for h in hl: 
     result[(d,h)] = 0 
     for diff in range((end-start).days*24): 
      comp = start + datetime.timedelta(hours=diff) 
      if comp.isoweekday() == d and comp.hour == h: 
       result[(d,h)] += 1 

 

>>> result 
{(3, 12): 5, (5, 13): 6, (3, 13): 5, (1, 23): 5, (2, 11): 5, (3, 11): 5, (4, 14): 6, (4, 13): 6, (4, 12): 6, (2, 12): 5, (2, 14): 5, (3, 14): 5, (1, 9): 5} 

Sarò anche provare per una soluzione con timestamp() e %.

2

Ecco un'altra soluzione con l'aritmetica:

import datetime 

pairs = {1: [9,23], 
2: [11, 12, 14], 
3: [11, 12, 13, 14], 
4: [12, 13, 14], 
5: [13], 
6: [], 
7: [] 
} 

start = datetime.datetime(2015, 7, 22, 17, 58, 54, 746784) 
end = datetime.datetime(2015, 8, 30, 10, 22, 36, 363912) 
result={} 
weeks = (end-start).days//7 

for d,hl in pairs.items(): 
    for h in hl: 
     initial = weeks 
     if d > start.isoweekday() or (
      d == start.isoweekday() and h >= start.hour): 
      initial += 1 
     result[(d,h)] = initial 

 

>>> for k in sorted(result): 
...  print(k, result[k]) 
... 
(1, 9) 5 
(1, 23) 5 
(2, 11) 5 
(2, 12) 5 
(2, 14) 5 
(3, 11) 5 
(3, 12) 5 
(3, 13) 5 
(3, 14) 5 
(4, 12) 6 
(4, 13) 6 
(4, 14) 6 
(5, 13) 6 
+0

Grazie! - Qualche ragione per credere che una delle soluzioni sia più efficiente dell'altra? (ad esempio, eseguendo il ciclo di centinaia di migliaia di esempi di coppie) –

+0

@ AmelioVazquez-Reina: non ne sono sicuro; Non l'ho provato Avevo solo il sospetto che un po 'di aritmetica sarebbe stata più veloce di un loop in ogni ora possibile. Se vuoi provare alcune di queste soluzioni e farci sapere i tuoi risultati, sarei interessato a vederli. – TigerhawkT3

+0

Per chiarire, non ho verificato la _performance relativa di ciascun algoritmo. – TigerhawkT3