我有一个对象列表:带有id,日期和对象类型的指示。例如
original_list = [{'id':1,'date':'2016-01-01','type':'A'},
{'id':2,'date':'2016-02-01','type':'B'},
{'id':3,'date':'2016-03-01','type':'A'},
{'id':1,'date':'2016-04-01','type':'C'}]
如上所示,此列表可以包含重复的ID和不同的日期,类型。现在我想创建一个唯一ID的列表,其中只包含最后的条目(基于日期)。现在我有一个程序如下:
# Create list of unique id's
unique_ids = list(set([foo.get('id') for foo in original_list]))
# find last contact
for unique_id in unique_ids:
foo_same_id = [foo for foo in original_list if foo.get('id') == unique_id]
if len(foo_same_id) == 1:
# use this one
else:
latest_date = [foo.get('date') for foo in foo_same_id]
latest_date = max(latest_date)
latest_object = [foo for foo in foo_same_id if foo.get('date') == latest_date]
在此之后,具有相同id的列表在日期上排序,并且是用于填充对象类型的类型的最后一个值。那时我不再需要这些对象,并且在没有处理过的对象/ id的情况下复制两个列表(original_list和unique_ids)。
这似乎有效但是当应用到200.000 +时需要花费很多时间(+ 4小时)。有办法加快速度吗?不同的实施?目前我正在读取数据库中的数据并立即开始处理。
答案 0 :(得分:1)
而不是使用set和其他额外操作创建所有唯一ID,然后循环遍历列表并使用所有这些额外的操作
操作,您可以简单地使用自定义词典,以便根据其ID保留您的词典。并且由于字典只保留
如果您覆盖__setitem__
方法的唯一项目,它只会根据日期替换值(如果它大于当前值)
你只需创建你的欲望清单。
from datetime import datetime
class UniqueDict(dict):
def __init__(self, *args, **kwds):
super(UniqueDict, self).__init__(*args, **kwds)
def __setitem__(self, _id, value):
current = self.get(_id)
if current:
date_obj = datetime.strptime(value['date'], '%Y-%m-%d')
current_date_obj = datetime.strptime(self[_id]['date'], '%Y-%m-%d')
if date_obj > current_date_obj:
dict.__setitem__(self, _id, value)
else:
dict.__setitem__(self, _id, value)
演示:
original_list = [{'id':1,'date':'2016-01-01','type':'A'},
{'id':2,'date':'2016-02-01','type':'B'},
{'id':3,'date':'2016-03-01','type':'A'},
{'id':1,'date':'2016-04-01','type':'C'}]
udict = UniqueDict()
for d in original_list:
udict[d['id']] = d
print(udict)
输出:
{1: {'id': 1, 'date': '2016-04-01', 'type': 'C'},
2: {'id': 2, 'date': '2016-02-01', 'type': 'B'},
3: {'id': 3, 'date': '2016-03-01', 'type': 'A'}}
注意如评论中所述,在这种情况下,您也可以使用datetime
将日期字符串转换为日期对象进行比较,因为ISO格式的日期可以按字典顺序进行比较。
答案 1 :(得分:0)
使用自定义函数对原始文件进行重复处理,该函数仅遍历列表一次并在最后展平它:
def dedup_original(original):
items = {}
for item in original:
if item['id'] in items:
if items[item['id']]['date'] < item['date']:
items[item['id']] = item
else:
items[item['id']] = item
return list(items.values())
结果:
In [28]: dedup_original(original_list)
Out[28]:
[{'date': '2016-04-01', 'id': 1, 'type': 'C'},
{'date': '2016-02-01', 'id': 2, 'type': 'B'},
{'date': '2016-03-01', 'id': 3, 'type': 'A'}]