过滤列表以获得独特的和最新的项目

filter list to get unique and latest items

从列表中只获取唯一和最新项目的最佳方法是什么? 我想出的一种方法:

from itertools import groupby
from collections import namedtuple
from datetime import date

Event = namedtuple('Event', ('id', 'type', 'date'))

event_1 = Event(id=1, type='income', date=date(2020, 1, 5))
event_2 = Event(id=1, type='income', date=date(2020, 1, 10))
event_3 = Event(id=1, type='income', date=date(2020, 1, 8))

event_4 = Event(id=2, type='outcome', date=date(2020, 1, 9))
event_5 = Event(id=2, type='outcome', date=date(2020, 1, 15))


data = [event_1, event_2, event_3, event_4, event_5]


grouped = groupby(sorted(data, key=lambda e: (e.id, e.type, -e.date)), key=lambda e: (e.id, e.type))

unique_latest = [next(item[1]) for item in grouped]

所以结果应该是:unique_latest = [event_2, event_5].

所以我按唯一性标准(id、类型)分组并取每组的第一项。

但这种方法不能保证第一项是其组中的最新项。

尝试过 sorted(data, key=lambda e: (e.id, e.type, -e.date)),但 python 不允许 -e.date

这只是因为 datetime.

的负数(一元负)未定义

从较大的日期(例如,明年)中减去该日期,然后使用 timedelta 结果进行排序。

grouped = groupby(sorted(data, key=lambda e: (e.id, e.type,
                            date(2021, 12, 31) - e.date)),
                         key=lambda e: (e.id, e.type))

结果:

[Event(id=1, type='income', date=datetime.date(2020, 1, 10)),
 Event(id=2, type='outcome', date=datetime.date(2020, 1, 15))]

如果您使用 datetime 对象而不是 date,您可以使用 datetime.timestamp() 将值转换为浮点数,然后可以取反进行排序:

from itertools import groupby
from collections import namedtuple
from datetime import datetime

Event = namedtuple('Event', ('id', 'type', 'date'))

event_1 = Event(id=1, type='income', date=datetime(2020, 1, 5))
event_2 = Event(id=1, type='income', date=datetime(2020, 1, 10))
event_3 = Event(id=1, type='income', date=datetime(2020, 1, 8))

event_4 = Event(id=2, type='outcome', date=datetime(2020, 1, 9))
event_5 = Event(id=2, type='outcome', date=datetime(2020, 1, 15))


data = [event_1, event_2, event_3, event_4, event_5]


grouped = groupby(sorted(data, key=lambda e: (e.id, e.type, -e.date.timestamp())), key=lambda e: (e.id, e.type))

unique_latest = [next(item[1]) for item in grouped]

print(unique_latest)

输出:

[
 Event(id=1, type='income', date=datetime.datetime(2020, 1, 10, 0, 0)),
 Event(id=2, type='outcome', date=datetime.datetime(2020, 1, 15, 0, 0))
]