首页 > 解决方案 > Python:如何有效地将 4 个字典列表嵌套到一个中?

问题描述

我有一个 MSSQL 存储过程,它返回 4 个选项给我:EntitiesCertificates和. 我需要在 Pyton 中将这 4 个选项组合在一起,我将所有选项放在了它们的. 这些选择中的每一个都有一个我可以用于合并。ContactsLogsEntitiesContactsLogsCertificateEntityId

输入是简单的基本数据类列表,其中包含来自 SQL 的信息。我们将这些数据类转换为合并函数内的字典。

当我最初编写代码时,我不知道选择可能非常大(Certificates包括所有其他记录的 100.000 个)。不幸的是,由于循环内列表推导的许多不必要的迭代,这使得下面的代码非常低效。最多可能需要 70 秒。我确信有一种方法可以使这更快。如何提高性能以尽可能高效?

from dataclasses import asdict

def cert_and_details(entities: List[Entity], 
                    certificates: List[Certificate], 
                    req_logs: List[DocumentRequestHistory], 
                    recipients: List[Recipient]) -> List[dict]:

    entities = [asdict(ent) for ent in entities] 
    certificates = [asdict(cert) for cert in certificates]
    req_logs = [asdict(log) for log in req_logs]
    recipients = [asdict(rec) for rec in recipients]

    results = []
    for cert_dict in certificates:

        cert_entity_id = cert_dict["entityid"]

        logs_under_cert = [log for log in req_logs if log["entityid"] == cert_entity_id]
        cert_dict["logs"] = logs_under_cert

        entities_under_cert = [ent for ent in entities if ent["entityid"] == cert_entity_id]
        cert_dict["linkedentity"] = entities_under_cert

        recipients_under_cert = [rec for rec in recipients if rec["entityid"] == cert_entity_id]
        cert_dict["recipients"] = recipients_under_cert

        results.append(cert_dict)

    return results

标签: pythonperformancerestrecordpython-dataclasses

解决方案


提供的代码的主要问题是它的计算复杂性:它运行在O(C * (L + E + R))证书C数量L 、日志E数量、实体R数量和接收者数量的位置。如果很小,这很好L+E+R,但如果不是这种情况,那么代码会很慢。

您可以编写一个O(C + L + E + R)及时运行的实现。这个想法是首先建立一个索引,以按实体 ID 对日志/实体/收件人进行分组。这是一个简短的例子:

# Note: defaultdict should help to make this code smaller (and possibly faster)
logIndex = dict()
for log in req_logs:
    entityId = log["entityid"]
    if entityId in logIndex:
        logIndex[entityId].append(log)
    else:
        logIndex[entityId] = [log]

此代码在 (amortized) 中运行O(L)。然后,您可以使用仅检索req_log具有给定实体 ID 的所有项目logIndex[entityId]

提供的代码中还有另一个问题:字典列表效率低下:字典索引很慢,字典也不是内存效率。存储和计算数据的更好方法是使用数据帧(例如,使用也提供相对优化功能的Pandasgroupby)。


推荐阅读