使用for循环在字典中创建内部键

3

我正在使用for循环从表格创建一个字典。目标是使用for循环创建一个具有嵌套键值对的字典。

该表以文本格式存在。第一行是标题,如下所示:

AAA|BBB|CCC
zzz|100|xy
zzz|50|xy
xxx|200|xy
xxx|100|xy
zzz|300|xz
zzz|400|xz
xxx|200|xz
xxx|700|xz

要通过AAA获取总数(在AAA:CCC键值对中),以下代码是成功的:
dict = {}

with open('data.txt') as table:
    table.readline()
    for line in table:
        (AAA, BBB, CCC) = line.split("|")
        dict[AAA] = dict[AAA] + int(BBB) if AAA in dict else int(BBB)


输出结果如预期:
{'zzz': 850, 'xxx': 1200}

下一步(我卡住的地方)是如何执行迭代以创建内部键,格式为:
{'zzz':{xy:150, xz:700}, 'xxx':{xy:300, xz:900}}

这是我目前的进展,但我不知道如何将insideKey插入到这个字典中:
dict = {}
new_dict = {}

with open('data.txt') as table:
    table.readline()
    for line in table:
        (AAA, BBB, CCC) = line.split("|")
        dict[AAA] = dict[AAA] + (new_dict[CCC] + int(BBB)) if CCC in new_dict else int(BBB)



我知道不能使用+添加insideKey,但是找不到做这件事的方法。
期望输出:
{'zzz':{xy:150, xz:700}, 'xxx':{xy:300, xz:900}}

你想对重复的值做什么:xxx|200|xy xxx|100|xy{xxx:{ xy:?}} 应该是什么? - Mark
Mark Meyer:看起来 N N 想要对它们求和。 - John Ladasky
Mark,需要将它们相加,{xxx:{xy:300}}。可以把xxx看作是一个苹果,200是数量,xy是购买这个数量的人Kevin。在下一个实例中,xxx-苹果,数量为100,也是由Kevin(xy)购买。xz可能是另一个人,比如Mike。因此,我们的字典键和值将是{apple:{Kevin:300, Mike:900}} - N N
3个回答

1
你可以使用 setdefault() 设置初始值。在循环中,只需设置适当的默认值或使用 get 获取内部值或零:
d = {}
with open('data.txt') as table:
    next(table)
    for line in table:
        (AAA, BBB, CCC) = map(str.strip, line.split("|"))
        outer = d.setdefault(AAA, {})
        outer[CCC] = outer.get(CCC, 0) + int(BBB)

result:

{'zzz': {'xy': 150, 'xz': 700}, 'xxx': {'xy': 300, 'xz': 900}}

1

一个快速的建议:不要使用“dict”作为字典实例的名称,因为它也是字典类的名称。Python允许您修改内置名称的绑定。这很强大,但如果您在那之后需要使用dict()构造函数,则无法执行。

现在,回到你的问题。我认为你试图在太少的代码行中完成太多的任务。没有必要在字典赋值处编写多个明确的行。我还建议您通过构建更简单的字典作为中间步骤来重新组织问题。

字典键可以是任何可哈希的不可变数据类型。这包括仅包含不可变数据的元组。该程序按您想要的方式给出了总和数据,但并不完全是您想要的方式组织的:

dct = {}
with open('data.txt') as table:
    table.readline()
    for line in table:
        (AAA, BBB, CCC) = line.split("|")
        v = int(BBB)     # value
        k = (AAA, CCC)   # key
        try:
            dct[k] += v  # existing key
        except KeyError:
            dct[k] = v   # new key

此时,dct 包含:
{('zzz', 'xy'): 150, ('xxx', 'xy'): 300, ('zzz', 'xz'): 700, ('xxx', 'xz'): 900}

现在,使用第二个循环来创建一个新的字典,按你想要的方式重新组织。
result = {}
for (k1, k2), v in dct.items():
    try:
        result[k1][k2] = v
    except KeyError:
        result[k1] = {k2 : v}

这是关于 result 的内容:
{'zzz': {'xy': 150, 'xz': 700}, 'xxx': {'xy': 300, 'xz': 900}}

我使用了三个技巧,这些技巧可能是初学Python的程序员不知道的:比字符串或数字更复杂的字典键;异常处理;以及元组解包。如果你还没有学习这些概念,你可能会发现它们非常有用。
注意:如果你可以使用第三方包,Pandas DataFrames是完成这种工作的好工具。不过,只有当你需要处理大量数据时,Pandas才值得付出努力。

0

只是为了说明使用defaultdict。

from collections import defaultdict

d = defaultdict(dict)

with open('f0714.txt', 'r') as table:
    next(table)
    for line in table:
        (AAA, BBB, CCC) = map(str.strip, line.split("|"))

        if CCC not in d[AAA]:
            d[AAA][CCC] = int(BBB)
        else:
            d[AAA][CCC] += int(BBB)

print(dict(d))

'''
{'zzz': {'xy': 150, 'xz': 700}, 'xxx': {'xy': 300, 'xz': 900}}
'''

1
此时可以全力以赴:d = defaultdict(lambda: defaultdict(lambda: 0)),以跳过 if,然后使用 print({k: dict(v) for k, v in dict(d).items()}) 来移除内部的 defaultdict。 - Mephy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接