Trova valore massimo di tempo in lista contenente tuple di ora nel formato ( 'ora', 'min', 'AM / PM')

voti
5

Ho una lista di di tuple che rappresentano momenti diversi

timeList = [('4', '12', 'PM'), ('8', '23', 'PM'), ('4', '03', 'AM'), ('1', '34', 'AM'), 
('12', '48', 'PM'), ('4', '13', 'AM'), ('11', '09', 'AM'), ('3', '12', 'PM'), 
('4', '10', 'PM')]

Voglio tornare il massimo dalla lista, dopo qualche ricerca ho capito che potevo usare la chiave nella massima per cercare per l'AM o PM prima.
print(max(timeList, key = operator.itemgetter(2)))

Quando eseguo questo però, sto ottenendo il massimo sbagliata ('4', '12', 'PM') Ci ho pensato, e non solo non ha senso, dato che dovrebbe essere 8:23 max, ma ho anche capito che sarebbe probabilmente 12:48 max tornare dal momento che è un PM e anche tecnicamente superiore a 8 nella mia ricerca.

Detto questo, come potrei ottenere questo massimo per trovare le ultime tempo possibile, data la formattazione della lista non può essere modificato.

È pubblicato 15/02/2018 alle 22:21
dall'utente
In altre lingue...                            


6 risposte

voti
2

keyparam con la maxfunzione viene utilizzata per informare maxsu quale valore si desidera eseguire l'operazione max. itemgetter(2)recupera il valore a seconda dell'indice, e lessicografico "PM" è il valore più alto nella lista in indice 2 (lessicografico 'PM'> 'AM'). È possibile utilizzare una lambda funzione per calcolare il massimo su tupla in corrispondenza dell'indice 0 e 1 come:

>>> timeList = [('4', '12', 'PM'), ('8', '23', 'PM'), ('4', '03', 'AM'), ('1', '34', 'AM'), ('12', '48', 'PM'), ('4', '13', 'AM'), ('11', '09', 'AM'), ('3', '12', 'PM'), ('4', '10', 'PM')]

# type-casting it to `int` to avoid incorrect result 
# due lexicographical comparision of `str`
>>> max(timeList, key=lambda x: (x[2], int(x[0]), int(x[1])))
('12', '48', 'PM')            #   ^      ^         ^ Third priority to `int` value of minute
                              #   ^      ^ Second priority to int value of `hour`
                              #   ^ First priority to lexicographically sort on `AM`/`PM`

O, si esegue il confronto sul datetime.datetimeoggetto come:

>>> from datetime import datetime

>>> max(timeList, key=lambda x: datetime.strptime('{}:{}{}'.format(*x), '%I:%M%p'))
('8', '23', 'PM')

Penso che si dovrebbe aver creato l'elenco dei datetime.datetimeinvece di tempo tuplesinizialmente.

Risposto il 15/02/2018 a 22:24
fonte dall'utente

voti
5

Basta definire una funzione chiave appropriata. Si vuole int(hour), int(minute)e 'PM'già sorta lessicografico superiore "AM", ma deve essere considerato prima , quindi. Inoltre, è necessario prendere le ore 12 del modulo, in modo che 12smista meno di altri numeri, all'interno di un pm/ am:

In [39]: timeList = [('4', '12', 'PM'), ('8', '23', 'PM'), ('4', '03', 'AM'), ('1', '34', 'AM'),
    ...: ('12', '48', 'PM'), ('4', '13', 'AM'), ('11', '09', 'AM'), ('3', '12', 'PM'),
    ...: ('4', '10', 'PM')]

In [40]: def key(t):
...:     h, m, z = t
...:     return z, int(h)%12, int(m)
...:

In [41]: max(timeList,key=key)
Out[41]: ('8', '23', 'PM')

Ma ciò che renderebbe più senso è di utilizzare effettivamente datetime.timegli oggetti, invece di fingere una tupla di stringhe è un buon modo per memorizzare il tempo.

Quindi, qualcosa di simile a:

In [49]: def to_time(t):
    ...:     h, m, z = t
    ...:     h, m = int(h)%12, int(m)
    ...:     if z  == "PM":
    ...:         h += 12
    ...:     return datetime.time(h, m)
    ...:

In [50]: real_time_list = list(map(to_time, timeList))

In [51]: real_time_list
Out[51]:
[datetime.time(16, 12),
 datetime.time(20, 23),
 datetime.time(4, 3),
 datetime.time(1, 34),
 datetime.time(12, 48),
 datetime.time(4, 13),
 datetime.time(11, 9),
 datetime.time(15, 12),
 datetime.time(16, 10)]

In [52]: list(map(str, real_time_list))
Out[52]:
['16:12:00',
 '20:23:00',
 '04:03:00',
 '01:34:00',
 '12:48:00',
 '04:13:00',
 '11:09:00',
 '15:12:00',
 '16:10:00']

Nota, ora max"funziona solo":

In [54]: t = max(real_time_list)

In [55]: print(t)
20:23:00

E se avete bisogno di una bella stringa da stampare, basta fare la formattazione a quel punto:

In [56]: print(t.strftime("%I:%M %p"))
08:23 PM
Risposto il 15/02/2018 a 22:31
fonte dall'utente

voti
4

Perché non aggiungi la struttura ai vostri dati?

from datetime import datetime

max(datetime.strptime(''.join(x), '%I%M%p') for x in timeList)

# datetime.datetime(1900, 1, 1, 20, 23)
# i.e. 8.23pm

Mentre si dice "la formattazione di elenco non dovrebbe essere cambiata", che è esattamente ciò che tutte le soluzioni sono implicitamente facendo al fine di eseguire i confronti.

Risposto il 15/02/2018 a 22:34
fonte dall'utente

voti
-1

sembra che tu timeList sono volte. forse ha senso l'analisi di come tale?

 max([datetime.strptime("{}:{} {}".format(t[0],t[1],t[2]),'%I:%M %p') for t in timeList]).strftime("%H:%M")
Risposto il 15/02/2018 a 22:37
fonte dall'utente

voti
1

Aggiungendo le soluzioni si possono anche ordinare con datetime:

from datetime import datetime

timeList = [('4', '12', 'PM'), ('8', '23', 'PM'), ('4', '03', 'AM'), ('1', '34', 'AM'), 
('12', '48', 'PM'), ('4', '13', 'AM'), ('11', '09', 'AM'), ('3', '12', 'PM'), 
('4', '10', 'PM')]

sorted(timeList, key=lambda x: datetime.strptime(''.join(x), '%I%M%p'))[-1]

Ritorna:

('8', '23', 'PM')
Risposto il 15/02/2018 a 23:07
fonte dall'utente

voti
0

Questo è veramente elegante implementato in panda, che permette una MultiIndex, che possiamo quindi ordinare e prendere la testa:

import numpy as np
import pandas as pd

timeList = [('4','12','PM'),  ('8','23','PM'),  ('4','03','AM'),
            ('1','34','AM'),  ('12','48','PM'), ('4','13','AM'),
            ('11','09','AM'), ('3','12','PM'),  ('4','10','PM')]

timeDf = pd.DataFrame(timeList, columns=['hr','min','meridiem'])
timeDf.set_index(['meridiem','hr','min'], inplace=True, drop=True)

#timeDf['value'] = np.random.randint(1,10, timeDf.shape[0]) # np.nan

timeDf.sort_index(level=0, ascending=False, inplace=True) # sort by meridiem, then the remaining cols (alphanumeric string comparison)
timeDf.index[0]
# ('PM', '8', '23')

Gli appunti:

  • Se si desidera mantenere hr,min,meridiemcome colonne nella vostra df, quindi utilizzareset_index(..., drop=False)
  • come sottolinea AntonvBR, se il timestamp comprendeva anche un fuso orario, allora potremmo più utilizzare un semplice ordinamento su più (stringa) campi distinti; vorremmo calcolare la datetime sottostante quindi utilizzarlo come chiave di ordinamento.
Risposto il 15/02/2018 a 23:51
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more