如果一个字典中的键与另一个字典中的键匹配,我该如何返回一个新的字典?

17

目前,我有一个字典,其键表示邮政编码,值也是一个字典。

d = { 94111: {'a': 5,  'b': 7,  'd': 7}, 
      95413: {'a': 6,  'd': 4}, 
      84131: {'a': 5,  'b': 15, 'c': 10, 'd': 11}, 
      73173: {'a': 15, 'c': 10, 'd': 15}, 
      80132: {'b': 7,  'c': 7,  'd': 7} }

然后是第二个字典,它将邮政编码对应到所属的州。

states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}
如果字典中的邮政编码statesdb中的某个键匹配,则会将这些值相加并放入新的字典中,就像预期输出一样。

预期输出:

{'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}

目前这是我想要追求的方向,但当两个密钥匹配时,我不确定如何创建一个类似于预期输出的字典。

def zips(d, states):
    result = dict()
    for key, value in db.items():
        for keys, values in states.items():
            if key == keys:


zips(d, states)
7个回答

11

使用 collections 模块

例子:

from collections import defaultdict, Counter

d = { 94111: {'a': 5,  'b': 7,  'd': 7}, 
      95413: {'a': 6,  'd': 4}, 
      84131: {'a': 5,  'b': 15, 'c': 10, 'd': 11}, 
      73173: {'a': 15, 'c': 10, 'd': 15}, 
      80132: {'b': 7,  'c': 7,  'd': 7} }

states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}

result = defaultdict(Counter)
for k,v in d.items():
    if k in states:
        result[states[k]] += Counter(v)
print(result)

输出:

defaultdict(<class 'collections.Counter'>, {'AL': Counter({'d': 26, 'a': 21, 'c': 17, 'b': 7}), 
'TX': Counter({'b': 22, 'd': 18, 'a': 10, 'c': 10})})

我曾认为使用集合类比内置容器更快,但经过测试发现你的解决方案更慢,为什么? - T.Lucas
嗨@Rakesh,为什么你要使用defaultdict而不是普通的dict?是否有特殊原因? - Swadhikar
@SwadhikarC..https://www.accelebrate.com/blog/using-defaultdict-python/ - Rakesh
1
@T.Lucas Counter 至少是一个纯 Python 的用户定义子类,继承自 dict。它没有比单独使用 dict 更快的理由。 - chepner

2

你可以在循环中使用defaultdict和count:

最初的回答

expected_output = defaultdict(lambda: defaultdict(int))
for postcode, state in states.items():
     for key, value in d.get(postcode, {}).items():
         expected_output[state][key] += value

defaultdict(Counter)是什么意思? - Solomon Ucko

1
你可以利用 dict.items() 方法,该方法返回一个元组列表,并在一行代码中获得期望的输出: new_dict = {value:d[key] for key, value in states.items()} 输出结果: {'AL': {'b': 7, 'c': 7, 'd': 7}, 'TX': {'a': 5, 'b': 15, 'c': 10, 'd': 11}}

1

作为对Rakesh答案的补充,这里是一份更接近你代码的答案:

res = {v:{} for v in states.values()}

for k,v in states.items():
    if k in d:
        sub_dict = d[k]
        output_dict = res[v]
        for sub_k,sub_v in sub_dict.items():
            output_dict[sub_k] = output_dict.get(sub_k, 0) + sub_v

1
您可以使用类似这样的代码:

您可以使用类似这样的代码:

d = { 94111: {'a': 5,  'b': 7,  'd': 7},                                                                                                                                                
      95413: {'a': 6,  'd': 4},                                                                 
      84131: {'a': 5,  'b': 15, 'c': 10, 'd': 11},                                              
      73173: {'a': 15, 'c': 10, 'd': 15},                                                       
      80132: {'b': 7,  'c': 7,  'd': 7} }                                                       
states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}                         

out = {i: 0 for i in states.values()}                                                              
for key, value in d.items():                                                                       
    if key in states:                                                                              
        if not out[states[key]]:                                                                   
            out[states[key]] = value                                                               
        else:                                                                                      
            for k, v in value.items():                                                             
                if k in out[states[key]]:                                                          
                    out[states[key]][k] += v                                                       
                else:                                                                              
                    out[states[key]][k] = v                                                        
# out -> {'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}

1
你可以使用类Counter来计数对象:
from collections import Counter

d = { 94111: {'a': 5,  'b': 7,  'd': 7}, 
      95413: {'a': 6,  'd': 4}, 
      84131: {'a': 5,  'b': 15, 'c': 10, 'd': 11}, 
      73173: {'a': 15, 'c': 10, 'd': 15}, 
      80132: {'b': 7,  'c': 7,  'd': 7} }

states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}

new_d = {}
for k, v in d.items():
    if k in states:
        new_d.setdefault(states[k], Counter()).update(v)

print(new_d)
# {'TX': Counter({'b': 22, 'd': 18, 'a': 10, 'c': 10}), 'AL': Counter({'d': 26, 'a': 21, 'c': 17, 'b': 7})}

你可以将new_d转换为字典的字典:
for k, v in new_d.items():
    new_d[k] = dict(v)

print(new_d)
# {'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}

0
你可能需要重新考虑使用字典来存储数据的选择。如果你使用 pandas 存储数据,聚合会更加容易。
df = pd.DataFrame(d).transpose()
df['states']=pd.Series(states)
df.groupby('states').sum()

>>            a     b     c     d
>>states                        
>>AL      21.0   7.0  17.0  26.0
>>TX      10.0  22.0  10.0  18.0

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