如何简化这些词典的理解?

2024-09-30 19:36:59 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的代码正在工作,并带来了我想要的结果。然而,有两套两本词典的理解,我无法转换成两本词典的理解。可能吗

dicTfAll={1:{'c1': ['aa','bb','cc']},
         2:{'c1': ['dd','ee','ff']}}


dicTf={1:{'c2': ['aax','bbx','cc']},
         2:{'c2': ['ddy','eey','ff']},
         3: {'c2': ['xx', '11']}}

allKeys=list(dicTfAll.keys())
dicTfAllP1={item[0]:item[1]  for item in dicTf.items() if item[0] not in allKeys}
dicTfAllP2={item[0]:dict(dicTfAll[item[0]],**item[1])  for item in dicTf.items() if item[0] in allKeys}
dicTfAllP=dicTfAllP1
dicTfAllP.update(dicTfAllP2)
# I use at this point dicTfAllP to do a lot of calculations. 
# dicTfAllP has the same form but very different values. 
allKeys=list(dicTfAllP.keys())
listOfCompanies=['c1','c2']
outputCompanies={}
for company in listOfCompanies:
    theKeys=[key for key in allKeys if company in dicTfAllP[key]]
    outputCompanies[company]={token:key  for key in theKeys for token in dicTfAllP[key][company]}

准确地说,我想在一个字典理解中转换下面的这些行[它生成一个嵌套字典,它是上述字典的合并]:

allKeys=list(dicTfAll.keys())
dicTfAllP1={item[0]:item[1]  for item in dicTf.items() if item[0] not in allKeys}
dicTfAllP2={item[0]:dict(dicTfAll[item[0]],**item[1])  for item in dicTf.items() if item[0] in allKeys}

此外,我还想在一个字典理解中转换下面的这些行[它构建一个嵌套字典,恢复原始字典(合并之前)]:

outputCompanies={}
for company in listOfCompanies:
    theKeys=[key for key in allKeys if company in dicTfAllP[key]]
    outputCompanies[company]={token:key  for key in theKeys for token in dicTfAllP[key][company]}

我特别担心实施的效率。如果我需要保持这种结构,该怎么办? 我必须保持这种结构,因为我必须在两组听写理解之间进行大量计算


Tags: keyinforif字典itemsitemcompany
2条回答

您可以使用以下理解构建dicTfAllP:

dicTfAllP = {k:{**dicTfAll.get(k,{}),**dicTf.get(k,{})} for k in set(dicTfAll).union(dicTf)}

对于输出公司,您需要itertools的groupby帮助:

from itertools import groupby
outputCompanies = {c:dict((k,v) for _,k,v in vs) for c,vs in groupby(sorted( (c,v,n) for n,cs in dicTfAllP.items() for c,vs in cs.items() for v in vs),key=lambda x:x[0])}

由于上面这行有点复杂,您可以对其进行分解以保持内容清晰:

companyPairs    = ((c,v,n) for n,cs in dicTfAllP.items() for c,vs in cs.items() for v in vs)
groupedData     = groupby(sorted(companyPairs),key=lambda x:x[0])
outputCompanies = {c:dict((k,v) for _,k,v in vs) for c,vs in groupedData }

检查中间结果可以让您了解发生了什么

理解是python的一个惊人特性,但它们并不总是最好的例子。与其创建大量变量并将它们混合在一起,不如一次处理一个变量。我确信可以从这段代码中榨出更多的汁,但这应该在可读性和处理能力之间提供一个很好的平衡。我检查了输出,以确保它与代码的输出相匹配

dicTfAll = {
    1: {'c1': ['aa', 'bb', 'cc']},
    2: {'c1': ['dd', 'ee', 'ff']}
}

dicTf = {
    1: {'c2': ['aax', 'bbx', 'cc']},
    2: {'c2': ['ddy', 'eey', 'ff']},
    3: {'c2': ['xx', '11']}
}

outputCompanies = {}

for d in [dicTfAll, dicTf]:
    for idx, records in d.items():
        for company, items in records.items():

            if company not in outputCompanies.keys():
                outputCompanies[company] = {}

            for item in items:
                outputCompanies[company][item] = idx

print(outputCompanies)
# {
#     'c2': {'11': 3, 'ddy': 2, 'eey': 2, 'cc': 1, 'xx': 3, 'ff': 2, 'bbx': 1, 'aax': 1}, 
#     'c1': {'aa': 1, 'bb': 1, 'cc': 1, 'dd': 2, 'ee': 2, 'ff': 2}
# }

由于您正在寻找性能更高的代码,下面是在jupyter实验室中使用%%timeit对运行时的比较

# My version
2.99 µs ± 30 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


# Original Version
6.39 µs ± 25.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

我还尝试了一个稍微紧凑一点的代码版本,但最终运行时间更长

%%timeit
outputCompanies = defaultdict(dict)

for d in [dicTfAll, dicTf]:
    for idx, records in d.items():
        for company, items in records.items():
            outputCompanies[company].update({item: idx for item in items})

# 4.88 µs ± 22.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

另一项测试实际上包括理解:

%%timeit
outputCompanies = {}

for d in [dicTfAll, dicTf]:
    for idx, records in d.items():
        for company, items in records.items():

            if company not in outputCompanies.keys():
                outputCompanies[company] = {}

            outputCompanies[company].update({
                item: idx for item in items
            })
# 4.99 µs ± 23.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

对于代码中的一些注释,dict.keys()返回一个list对象,因此不需要调用list(dict.keys())。也不需要创建变量allKeys,因为您可以在字典理解中调用dict.keys()。公司都是硬编码的,如果这是一个一次性的脚本,这是很好的,但如果您希望数据集随着时间的推移而扩展,这不是最好的。但是如果您想硬编码它们,可以跳过变量声明,只需键入for company in ['c1','c2']:。接下来,您可以通过创建等于第一个理解的dicTfAllP并使用第二个理解更新它来保存更多变量。把这些放在一起,你会得到下面的代码。它更具可读性,也更容易理解,但性能并没有提高多少

%%timeit
dicTfAllP = {
    item[0]:item[1]
    for item 
    in dicTf.items()
    if item[0] not in dicTfAll.keys()
}

dicTfAllP.update({
    item[0]: dict(dicTfAll[item[0]], **item[1])
    for item 
    in dicTf.items() 
    if item[0] in dicTfAll.keys()
})

outputCompanies = {}
for company in ['c1','c2']:
    theKeys = [key for key in dicTfAllP.keys() if company in dicTfAllP[key]]
    outputCompanies[company] = {
        token:key
        for key in theKeys 
        for token in dicTfAllP[key][company]
    }
# 6.11 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

相关问题 更多 >