这是将两个dicts结合在一起并将相似值相加的最佳方法

时间:2014-01-27 22:38:22

标签: python django dictionary django-models

是否有更快或更多" pythonic"实现这一目标的方法:

dicta = {'a':{'a1':1, 'a2':2}, 'b':{'b1': 1, 'b2': 2}}
dictb = {'b':{'b1':1, 'a2':2}, 'c':{'c1': 1, 'c2': 2}}
dictc = {}

dictc.update(dicta)
for outside_key in dictb:
    if outside_key in dictc:
        for inside_key in dictb[outside_key]:
            if inside_key in dictc[outside_key]:
                dictc[outside_key][inside_key] += dictb[outside_key][inside_key]
            else:
                dictc[outside_key][inside_key] = dictb[outside_key][inside_key]
    else:
        dictc[outside_key] = dictb[outside_key]

dictc现在包含以下内容:

{'a': {'a1': 1, 'a2': 2},
 'c': {'c2': 2, 'c1': 1},
 'b': {'a2': 2, 'b1': 2, 'b2': 2}}

我在django模型定义中使用它,上面似乎是描述问题最明显的方法,但后来我意识到它不够具体。

这是django代码的样子:

def get_capabilities(self):
    capabilities_dict = {}
    capabilities_list = ('card', 'module') #Two ManyToMany fields
    capabilities_dict.update(self.barebone.get_capabilities()) 
    # self.barebone.get_capabilities() is the only foreingkey field
    # and serves as the base on which we build the capabilities list.
    for capability in capabilities_list:
        instances = getattr(self, capability).all()
        for instance in instances:
            capabilities = instance.get_capabilities()
            for capability_name in capabilities:
                if capability_name in capabilities_dict:
                    for obj in capabilities[capability_name]:
                        if obj in capabilities_dict[capability_name]:
                            capabilities_dict[capability_name][obj] += capabilities[capability_name][obj]
                        else:
                            capabilities_dict[capability_name][obj] = capabilities[capability_name][obj]
                else:
                    capabilities_dict[capability_name] = capabilities[capability_name]
    return capabilities_dict

self.barebone.get_capabilities()看起来像这样:

{'compatible_bus_types': {<BusType: PCI-X>: 1},
 'compatible_storage_interfaces': {<StorageInterface: SATA>: 8},
 'compatible_storage_form_factors': {<StorageFormFactor: 3.5">: 4}}

并且上面的函数get_capabilities()返回:

{'compatible_network_connectors': {},
 'compatible_storage_interfaces': {<StorageInterface: SATA>: 8,
                                   <StorageInterface: SAS>: 8},
 'compatible_network_standards': {},
 'compatible_storage_form_factors': {<StorageFormFactor: 3.5">: 4},     
 'compatible_bus_types': {<BusType: PCI-X>: 1},
 'compatible_network_form_factors': {}}

每个&lt;&gt;封闭的&#34;内键&#34;实际上是另一个模型实例。

谢谢,

2 个答案:

答案 0 :(得分:3)

collections.Counter与普通字典一起使用:

>>> from collections import Counter
>>> dictc = {}
>>> for d in (dicta, dictb):
    for k, v in d.items():
        dictc[k] = dictc.get(k, Counter()) + Counter(v)
...         
>>> dictc
{'a': Counter({'a2': 2, 'a1': 1}),
 'c': Counter({'c2': 2, 'c1': 1}),
 'b': Counter({'a2': 2, 'b1': 2, 'b2': 2})}

或使用defaultdict

>>> from collections import Counter, defaultdict
>>> dictc = defaultdict(Counter)
>>> for d in (dicta, dictb):
    for k, v in d.items():
        dictc[k] += Counter(v)
...         
>>> dictc
defaultdict(<class 'collections.Counter'>,
{'a': Counter({'a2': 2, 'a1': 1}),
 'c': Counter({'c2': 2, 'c1': 1}),
 'b': Counter({'a2': 2, 'b1': 2, 'b2': 2})})

答案 1 :(得分:0)

您使用嵌套的dict,但我认为有一个更简单的数据结构:您可以使用元组,例如('a','a2') 作为键而不是。你的dicts看起来像这样:

dicta = {('a', 'a1'): 1, ('a', 'a2'): 2, ('b', 'b1'): 1, ('b', 'b2'): 2}
dictb = {('b', 'a2'): 2, ('b', 'b1'): 1, ('c', 'c1'): 1, ('c', 'c2'): 2}

访问这些值的方法如下:

print dicta['a', 'a1']
Out: 1

而不是

print dicta['a']['a1']
Out: 1

要将数据更改为该结构,您可以使用此功能:

def unnestdict(dct):
    return { (key1, key2):value 
                         for key1, sub_dct in dct.iteritems()
                             for key2, value in sub_dct.iteritems()}

如果您使用此数据结构,则可以轻松使用Counter中的collections - 类 - 模块:

from collections import Counter

counterC = Counter(dicta) + Counter(dictb)
print counterC
Out: Counter({('b', 'b2'): 2, ('a', 'a2'): 2, ('b', 'b1'): 2, ('b', 'a2'): 2, ('c', 'c2'): 2, ('a', 'a1'): 1, ('c', 'c1'): 1})

dictc = dict(counterC)
print dictc
Out: {('b', 'a2'): 2, ('b', 'b1'): 1, ('c', 'c1'): 1, ('c', 'c2'): 2}