创建唯一列表:比较dict对象

时间:2017-03-12 09:36:49

标签: python python-3.x date dictionary

我有一个对象列表:带有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小时)。有办法加快速度吗?不同的实施?目前我正在读取数据库中的数据并立即开始处理。

2 个答案:

答案 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'}]