我有一个代表不同时间的元组列表
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')]
我想从列表中返回最大值,经过一些搜索,我意识到我可以使用最大键来首先搜索AM或PM。
print(max(timeList, key = operator.itemgetter(2)))
但是,当我运行此操作时,我得到了错误的最大值('4', '12', 'PM')
我考虑过它,不仅没有意义,因为8:23应该是最大的,但是我也意识到12:48可能会返回最大值,因为它是下午和技术上大于8搜索范围。
话虽如此,如果无法更改列表的格式,我怎么能得到最大值才能找到最新的可能时间。
答案 0 :(得分:5)
只需定义适当的键功能即可。您希望int(hour)
,int(minute)
和'PM'
按字典顺序排序高于"AM"
,但应将其视为 first ,所以。此外,您需要采用小时模数12,以便12
在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')
但是最有意义的实际上是使用datetime.time
个对象,而不是假装一个字符串元组是一种存储时间的好方法。
类似于:
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']
注意,现在max
“正常”:
In [54]: t = max(real_time_list)
In [55]: print(t)
20:23:00
如果你需要一个漂亮的字符串来打印,那么只需要进行格式化:
In [56]: print(t.strftime("%I:%M %p"))
08:23 PM
答案 1 :(得分:4)
为什么不为您的数据添加结构?
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
虽然您说“不应更改列表的格式”,但这正是所有解决方案为执行比较而隐式执行的操作。
答案 2 :(得分:2)
key
函数的 max
参数用于通知max
您要执行最大操作的值。 itemgetter(2)
获取第二个索引处的值,按字典顺序“PM”是索引2列表中的最高值(按字典顺序排列'PM'>'AM')。您可以使用 lambda 函数计算索引0和1处元组的最大值:
>>> 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`
或者,您在datetime.datetime
对象上执行比较:
>>> from datetime import datetime
>>> max(timeList, key=lambda x: datetime.strptime('{}:{}{}'.format(*x), '%I:%M%p'))
('8', '23', 'PM')
我认为您应该最初创建datetime.datetime
而不是时间tuples
的列表。
答案 3 :(得分:1)
添加到解决方案,您还可以使用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]
返回:
('8', '23', 'PM')
答案 4 :(得分:0)
这在pandas中实现得非常优雅,它允许使用MultiIndex,然后我们可以对它进行排序并占据头部:
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')
注意:
hr,min,meridiem
作为df中的列,请使用set_index(..., drop=False)
答案 5 :(得分:-1)
看起来像你的时间列表。 也许它解析它是有道理的吗?
max([datetime.strptime("{}:{} {}".format(t[0],t[1],t[2]),'%I:%M %p') for t in timeList]).strftime("%H:%M")