如何根据最大值返回具有唯一元素的元组列表?

时间:2017-12-20 21:34:30

标签: python

我想返回一个具有唯一ID的元组列表,但特别是保留元组的最新日期。

唯一ID位于每个元组的第一个元素中(即1,2,3,4)。

日期存在于每个元组的多个元素中(元组的第3个元素和第6个元素)。

a = [(1,'Y', 'rat', datetime.datetime(2016, 12, 12, 0, 0), 'N', None),
(2,'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None),
(1,'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0)),
(2,'N', None, None, 'Y', datetime.datetime(2017, 3, 16, 0, 0)),
(3,'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None),
(4,'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]

我期待的输出是:

b = [(1,'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0)),
(2,'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None),
(3,'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None),
(4,'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]

我已将元组放入字典并使用groupby进行排序。

from itertools import groupby
dict={}
f = lambda x: x[0]
for key, group in groupby(sorted(a, key=f),f):
    dict[key] = list(group)

这是字典输出:

{1: [(1, 'Y', 'rat', datetime.datetime(2016, 12, 12, 0, 0), 'N', None), 
(1, 'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0))], 
2: [(2, 'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None), 
(2, 'N', None, None, 'Y', datetime.datetime(2017, 3, 16, 0, 0))], 
3: [(3, 'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None)], 
4: [(4, 'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]}

从这一步开始,我无法将我想要的字典值提取到新列表中。

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

首先,您可以定义一个函数来从元组中获取datetime,无论其位置如何。 然后你可以通过id和datetime反向排序列表,按ID分组,获取下一个条目,然后再次排序(因此它按ID排序)。

>>> getdate = lambda t: next(x for x in t if isinstance(x, datetime.datetime))
>>> sorted(next(g) for k, g in itertools.groupby(sorted(a, key=lambda t: (t[0], getdate(t)), reverse=True), key=lambda t: t[0]))
[(1, 'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0)),
 (2, 'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None),
 (3, 'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None),
 (4, 'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]

或稍微短一些,只按ID排序一次,然后按日期获取max;同样的结果:

>>> [max(g, key=getdate) for k, g in itertools.groupby(sorted(a), key=lambda t: t[0])]

当然,使用简单的循环和字典也可以(并且更快)...

d = dict()
for t in a:
    if t[0] not in d or getdate(d[t[0]]) < getdate(t):
        d[t[0]] = t

......但是,嘿,没有什么能比一个过于复杂的单行语更胜一筹!

答案 1 :(得分:0)

在我看来,你需要编写自定义代码。 python中没有内置函数来完成你想要实现的目标。

您可以使用经典的python代码或更多面向数据的库,例如Pandas。

主要思想是这一个

result = dict()

for item in a:
  if item[0] not in result:
     result[item[0]] = ...
  else:
     if result[item[0]][5] < item[5]:
        result[item[0]] = ...

我没有详细说明,这只是全球性和通用性的想法。

答案 2 :(得分:0)

你可以试试这个:

import datetime
import itertools
a = [(1,'Y', 'rat', datetime.datetime(2016, 12, 12, 0, 0), 'N', None),
 (2,'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None),
 (1,'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0)),
 (2,'N', None, None, 'Y', datetime.datetime(2017, 3, 16, 0, 0)),
 (3,'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None),
 (4,'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]
new_s = [d for c, d in [(a, sorted(list(b), key=lambda x:[h for h in x if type(h) == type(datetime.datetime(2017, 9, 17, 0, 0))][0], reverse=True)[0]) for a, b in itertools.groupby(sorted(a, key=lambda x:x[0]), key=lambda x:x[0])]]

输出:

[(1, 'N', None, None, 'Y', datetime.datetime(2017, 9, 17, 0, 0)), (2, 'Y', 'ox', datetime.datetime(2017, 9, 4, 0, 0), 'N', None), (3, 'Y', 'tiger', datetime.datetime(2013, 1, 18, 0, 0), 'N', None), (4, 'N', None, None, 'Y', datetime.datetime(2017, 10, 3, 0, 0))]