嵌套字典推导式

3

对于下面的嵌套字典,我想要分别对每个 'ab''bc''cd''de' 键的值进行求和。基本上,就是将字典折叠起来。最好使用带有 =sum 的推导式,但我无法找出正确的语法:

{'hot': {'111': {'ab': 1, 'bc': 3, 'cd': 5, 'de': 7}}}
{'hot': {'111': {'ab': 12.5, 'bc': -31, 'cd': 2.5, 'de': 13}}}
{'hot': {'111': {'ab': 10, 'bc': 3, 'cd': 0, 'de': -2}}}

{'hot': {'110': {'ab': -1, 'bc': 0, 'cd': 1, 'de': 1}}}
{'hot': {'110': {'ab': 8, 'bc': 20, 'cd': 41, 'de': 13}}}
{'hot': {'110': {'ab': 1.75, 'bc': 2.3, 'cd': 6, 'de': 0}}}

{'hot': {'109': {'ab': 2.7, 'bc': 24, 'cd': 4, 'de': 5}}}
{'hot': {'109': {'ab': 41, 'bc': 6, 'cd': 12, 'de': 33}}}
{'hot': {'109': {'ab': 32, 'bc': 7, 'cd': 18, 'de': 3.75}}}

{'cold': {'111': {'ab': 25, 'bc': 2, 'cd': 3, 'de': 2.1}}}
{'cold': {'111': {'ab': 5, 'bc': 8, 'cd': 5, 'de': 17}}}
{'cold': {'111': {'ab': -71, 'bc': 42, 'cd': 5, 'de': 16}}}

{'cold': {'110': {'ab': 23, 'bc': 2.4, 'cd': 2.1, 'de': 4.3}}}
{'cold': {'110': {'ab': 11, 'bc': 2.8, 'cd': 4.5, 'de': 2.4}}}
{'cold': {'110': {'ab': 4, 'bc': 5.7, 'cd': 8.7, 'de': 1}}}        

期望输出:

dict['hot']['111'][AB] = 1 + 12.5 + 10 = 23.5
dict['hot']['111'][BC] = 3 - 31 + 3 = - 25

etc


你想让所有的'ab'在一个总和中,还是想要对字典中每个相应键路径对应的所有'ab'求和(就像你期望的输出一样)? - Easton Bornemeier
3
你的输入不太清楚。你是在说你有多个键名相似的字典,并且想要按键名分组对值进行求和吗? - OldGeeksGuide
1
那不是一个合适的数据结构。 - cs95
你的输入会是什么? - anon
这些字典是否包含在列表中? - Gerrat
顺便问一下,数据是如何存储的?你需要一个文件读取器吗? - Jacob Birkett
2个回答

1
我假设你的数据是以列表形式存在的,因为这样可以得到你期望的答案。
data = [{'hot': {'111': {'ab': 1, 'bc': 3, 'cd': 5, 'de': 7}}},
{'hot': {'111': {'ab': 12.5, 'bc': -31, 'cd': 2.5, 'de': 13}}},
{'hot': {'111': {'ab': 10, 'bc': 3, 'cd': 0, 'de': -2}}},

{'hot': {'110': {'ab': -1, 'bc': 0, 'cd': 1, 'de': 1}}},
{'hot': {'110': {'ab': 8, 'bc': 20, 'cd': 41, 'de': 13}}},
{'hot': {'110': {'ab': 1.75, 'bc': 2.3, 'cd': 6, 'de': 0}}},

{'hot': {'109': {'ab': 2.7, 'bc': 24, 'cd': 4, 'de': 5}}},
{'hot': {'109': {'ab': 41, 'bc': 6, 'cd': 12, 'de': 33}}},
{'hot': {'109': {'ab': 32, 'bc': 7, 'cd': 18, 'de': 3.75}}},

{'cold': {'111': {'ab': 25, 'bc': 2, 'cd': 3, 'de': 2.1}}},
{'cold': {'111': {'ab': 5, 'bc': 8, 'cd': 5, 'de': 17}}},
{'cold': {'111': {'ab': -71, 'bc': 42, 'cd': 5, 'de': 16}}},

{'cold': {'110': {'ab': 23, 'bc': 2.4, 'cd': 2.1, 'de': 4.3}}},
{'cold': {'110': {'ab': 11, 'bc': 2.8, 'cd': 4.5, 'de': 2.4}}},
{'cold': {'110': {'ab': 4, 'bc': 5.7, 'cd': 8.7, 'de': 1}}}  ]

而且代码是这样的:

from collections import defaultdict
counts = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))

for d in data:                   # for the list
    for k1 in d:                 # for the hot-cold level
        for k2 in d[k1]:         # for the 1[0-9]{2} level
            for k3 in d[k1][k2]: # for the [a-z]{2} level
                counts[k1][k2][k3] += d[k1][k2][k3]

print(counts['hot']['111']['ab'])
print(counts['hot']['111']['bc'])

有两个级别的defaultdict嵌套。
输出:
23.5
-25

你不应该为此使用导入。这个人显然是Python中的新手,主要是关于组织数据的问题。你的例子有太多循环和额外开销。 - Jacob Birkett
你需要为每个嵌套深度使用一个循环。这就是 OP 数据的本质。 - cs95
@spikespaz 什么?不是的。我的意思是说,“你不应该为此使用导入”是错误的建议。对于刚开始学习编程的人,最好的建议是“不要重复造轮子”。 - juanpa.arrivillaga
@Coldspeed 我并不是在抨击你,而是在批评你,这并不是一件坏事。你的回答没有问题,我的也不比你的更好,我们只是针对我们认为 OP 想要表达的两个不同的事情进行回答。如果我给你留下了错误的印象,那我很抱歉。 - Jacob Birkett
如果批评是建设性的,我可以接受。但这对我来说毫无意义。如果您想要所有组合的总和,您能否给我一个不包含4个循环的解决方案?如果不能,请问我们为什么要讨论这个问题。 - cs95
显示剩余3条评论

0

这个例子是创建一个“getter”函数。与一次解析整个字典列表相比,它可能会减少一些开销。

这里的双重字典迭代可以通过在第一次迭代中简单地解析接受的字典来减少,但是为了演示目的,它被分成了accepted和第二个迭代器。

下面是一个完整的代码示例,它打印出所需的结果23.5。 首先,创建要从中读取的字典列表:

dictionaries = [
    {'hot': {'111': {'ab': 1, 'bc': 3, 'cd': 5, 'de': 7}}},
    {'hot': {'111': {'ab': 12.5, 'bc': -31, 'cd': 2.5, 'de': 13}}},
    {'hot': {'111': {'ab': 10, 'bc': 3, 'cd': 0, 'de': -2}}},

    {'hot': {'110': {'ab': -1, 'bc': 0, 'cd': 1, 'de': 1}}},
    {'hot': {'110': {'ab': 8, 'bc': 20, 'cd': 41, 'de': 13}}},
    {'hot': {'110': {'ab': 1.75, 'bc': 2.3, 'cd': 6, 'de': 0}}},

    {'hot': {'109': {'ab': 2.7, 'bc': 24, 'cd': 4, 'de': 5}}},
    {'hot': {'109': {'ab': 41, 'bc': 6, 'cd': 12, 'de': 33}}},
    {'hot': {'109': {'ab': 32, 'bc': 7, 'cd': 18, 'de': 3.75}}},

    {'cold': {'111': {'ab': 25, 'bc': 2, 'cd': 3, 'de': 2.1}}},
    {'cold': {'111': {'ab': 5, 'bc': 8, 'cd': 5, 'de': 17}}},
    {'cold': {'111': {'ab': -71, 'bc': 42, 'cd': 5, 'de': 16}}},

    {'cold': {'110': {'ab': 23, 'bc': 2.4, 'cd': 2.1, 'de': 4.3}}},
    {'cold': {'110': {'ab': 11, 'bc': 2.8, 'cd': 4.5, 'de': 2.4}}},
    {'cold': {'110': {'ab': 4, 'bc': 5.7, 'cd': 8.7, 'de': 1}}}
]

接下来,编写你的函数。

def get_sum(temp, num, pt):
    accepted = [] # Initialize a list of accepted dictionaries that fit the arguments passed.
    pt_sum = 0 # Initialize the variable for the sum of your parts, starting at 0.

    for dictionary in dictionaries: # Iterate through the dictionary list.
        if temp in dictionary and num in dictionary[temp]: # Check if the dict on current iteration has what you want.
            accepted.append(dictionary[temp][num]) # It does, so add it to accepted.
            # Let's pause here. Say you are reading the first dict in the list. So that means, this is what the fuction is working with:
            # {'hot': {'111': {'ab': 1, 'bc': 3, 'cd': 5, 'de': 7}}}
            # Now with the append function, we are calling "dictionary[temp][num]".
            # We know that each of these keys exist, because we just checked it.
            # So this eliminates the need to add the whole dictionary to "accepted".
            # Basically, we are cutting out the last section, because that's what we need. So you end up with:
            # "{'ab': 1, 'bc': 3, 'cd': 5, 'de': 7}" in the list "accepted".

    for dictionary in accepted: # Now go through the ones that have the data you need.
        pt_sum += dictionary[pt] # And simply add the value to the sum.

    return pt_sum # Return the part sum.

现在您可以使用它:

print(get_sum("hot", "111", "ab"))

>>> 23.5

我在顶部提到的简化代码是这样的:

def get_sum(temp, num, pt):
    pt_sum = 0

    for dictionary in dictionaries:
        if temp in dictionary and num in dictionary[temp]:
            pt_sum += dictionary[temp][num][pt]

    return pt_sum

基本上只是在第一个循环中添加到pt_sum,因此没有第二次迭代,这也从未被要求。

你并没有完全删除循环,只是在获取单个组合的总和。现在尝试获取它们所有的总和。 - cs95
@Coldspeed 这不是问题的关键点。从他说他想要使用它的方式来看,dict['hot']['111'][AB] 看起来像是在获取他已经知道的值。我给了他一个可以做到这一点的函数。基本上是相同的事情,只是用圆括号、引号和逗号代替方括号。 - Jacob Birkett
抱歉,数据来自于ElementTree的循环,从解析的xml中读取。我只是不想让问题过于繁琐。基本上是尝试将xml的部分存储到嵌套字典中,执行一些计算并保存为新的xml。 - gregV
@Vrun,我能在pastebin或其他地方看到解析器的输出吗? - Jacob Birkett

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