有没有一种更快的替代方法可以从字典列表中获取最新更新消息?

时间:2019-07-07 14:42:05

标签: python json python-2.7 performance dictionary

我需要从数据流中获取最新的更新消息。数据如下:

test_data = 
[{u'category': u'3',
  u'entity': u'entityA',
  u'length': u'0',
  u'timestamp': u'1562422690'},
 {u'category': u'3',
  u'entity': u'entityA',
  u'length': u'1',
  u'timestamp': u'1562422680'},
 {u'category': u'3',
  u'entity': u'entityB',
  u'length': u'2',
  u'timestamp': u'1562422691'},
 {u'category': u'3',
  u'entity': u'entityB',
  u'length': u'3',
  u'timestamp': u'1562422688'},
 {u'category': u'3',
  u'entity': u'entityC',
  u'length': u'4',
  u'timestamp': u'1562422630'},
 {u'category': u'3',
  u'entity': u'entityC',
  u'length': u'5',
  u'timestamp': u'1562422645'},
 {u'category': u'3',
  u'entity': u'entityD',
  u'length': u'6',
  u'timestamp': u'1562422645'}]

建议采用以下方法here

test_alexander = {entity: sorted([d for d in test_data if d.get('entity') == entity], key=lambda x: x['timestamp'])[-1]
     for entity in set(d.get('entity') for d in test_data)}

返回此值(它完全按预期工作):

{u'entityA': {u'category': u'3',
  u'entity': u'entityA',
  u'length': u'0',
  u'timestamp': u'1562422690'},
 u'entityB': {u'category': u'3',
  u'entity': u'entityB',
  u'length': u'2',
  u'timestamp': u'1562422691'},
 u'entityC': {u'category': u'3',
  u'entity': u'entityC',
  u'length': u'5',
  u'timestamp': u'1562422645'},
 u'entityD': {u'category': u'3',
  u'entity': u'entityD',
  u'length': u'6',
  u'timestamp': u'1562422645'}}

问题是我有7k个唯一的“实体”,并且“ test_data”中有多达700万个列表项。上面的解决方案需要很长时间,我想知道是否有更快的方法。

5 个答案:

答案 0 :(得分:1)

您应该能够通过一个单一的比较就可以做到这一点。在循环过程中,只需跟踪每个类别到目前为止所能看到的最大值即可:

from collections import defaultdict

def getMax(test_data):
    d = defaultdict(lambda: {'timestamp':0})

    for item in test_data:
        if int(item['timestamp']) > int(d[item['entity']]['timestamp']):
            d[item['entity']] = item
    return d

返回值将是一个字典,键为entity,每个字典的最大值。在循环中排序或构建数组的速度应该明显更快。仍然有700万需要一段时间。

答案 1 :(得分:1)

看起来像纯Python解决方案可能无法满足您的需求,我建议您使用pandas,它的性能可能会好得多。

你可以试试吗?

import pandas as pd

test_data = [{u'category': u'3',
              u'entity': u'entityA',
              u'length': u'0',
              u'timestamp': u'1562422690'},
             {u'category': u'3',
              u'entity': u'entityA',
              u'length': u'1',
              u'timestamp': u'1562422680'},
             {u'category': u'3',
              u'entity': u'entityB',
              u'length': u'2',
              u'timestamp': u'1562422691'},
             {u'category': u'3',
              u'entity': u'entityB',
              u'length': u'3',
              u'timestamp': u'1562422688'},
             {u'category': u'3',
              u'entity': u'entityC',
              u'length': u'4',
              u'timestamp': u'1562422630'},
             {u'category': u'3',
              u'entity': u'entityC',
              u'length': u'5',
              u'timestamp': u'1562422645'},
             {u'category': u'3',
              u'entity': u'entityD',
              u'length': u'6',
              u'timestamp': u'1562422645'}]

df = pd.DataFrame(test_data)
df["timestamp"] = df["timestamp"].astype(int)

print(df.loc[df.groupby("entity")["timestamp"].idxmax()].to_dict(orient='records'))

答案 2 :(得分:0)

您可以使用max代替sorted,因为您只需要最大的条目,而无需对其余项进行排序:

test_alexander = {entity: max([d for d in test_data if d.get('entity') == entity], key=lambda x: x['timestamp'])
                  for entity in set(d.get('entity') for d in test_data)}

((最大值将为O(n),排序将为O(n * logn))

答案 3 :(得分:0)

我将从按实体划分开始,然后使用max来获取每个实体的最新记录。这将具有线性复杂度。您具有的代码会进行过滤,然后对接近三次的每个实体进行记录排序。

在Python中,它看起来像:

partitions = dict()
for record in test_data:
    partitions.setdefault(record['entity'], []).append(record)
# replace this with defaultdict for 2x performance 

for key in partitions:
    partitions[key] = max(partitions[key], key=lambda x: int(x['timestamp']))

结果在partitions中。并且形状为{entity:[{}]}

可以通过用max调用代替累积来减少内存使用量,但这实际上可能会更慢。

答案 4 :(得分:0)

这应该可以解决问题。它会一次扫描测试数据并记录每个实体的最新消息:

from collections import defaultdict

latest_message = defaultdict(lambda: dict('timestamp'=0)

for data in test_data:
    latest = latest_message[data[entity]]
    if data['timestamp'] > latest['timestamp']:
        latest_message[data[entity]].update(data)