【问题标题】:Comparing nested dictionaries比较嵌套字典
【发布时间】:2018-08-01 09:23:07
【问题描述】:

我想比较嵌套字典如下:

d = {'siteA': {'00000000': 3, '11111111': 4, '22222222': 5},
        'siteB': {'00000000': 1, '11111111': 2, '22222222': 5}}

e = {'siteA': {'00000000': 5}}

f = {'siteB': {'33333333': 10}}

g = {'siteC': {'00000000': 8}}

d 是用于与efg 进行比较的完整字典总数。

如果 e 恰好在 siteA-00000000 中找到,那么我希望两个值(在本例中为 3 和 5)加起来为 8。

如果找不到f(在这种情况下是这样),我想将字典附加到d['siteB']

如果找不到g,想追加到d

谢谢!

【问题讨论】:

    标签: python dictionary counter


    【解决方案1】:

    collections.Counter 可用于对字典中的值求和并在它们不存在的地方添加键。由于Counterdict 的子类,因此不应破坏其他操作。除了一次性的转换成本外,它还非常高效且专为此类任务而设计。

    from collections import Counter
    
    # convert d to dictionary of Counter objects
    d = {k: Counter(v) for k, v in d.items()}
    
    # add items from e
    for k, v in e.items():
        if k in d:
            d[k] += Counter(e[k])
    
    # add item from f if not found
    for k, v in f.items():
        if k not in d:
            d[k] += Counter(f[k])
    
    # add item from g if not found
    for k, v in g.items():
        if k not in d:
            d[k] = Counter(v)
    

    结果:

    print(d)
    
    {'siteA': Counter({'00000000': 8, '11111111': 4, '22222222': 5}),
     'siteB': Counter({'00000000': 1, '11111111': 2, '22222222': 5}),
     'siteC': Counter({'00000000': 8})}
    

    【讨论】:

    • @ReverseEngineer,是的,没错。由于这种情况:If f is not found (in this case, it's true)。因为它找到了,所以什么也没有发生。
    • 知道了。感谢您的解决方案!
    • 奇怪,我尝试过使用这样的函数,但返回值没有添加到 d 中。 def update_dict(source, dest): source = {k: Counter(v) for k, v in source.items()} for k, v in dest.items(): if k not in source: source[k] = Counter(v) else: source[k] += Counter(dest[k]) 返回源
    【解决方案2】:

    您可以将collections 中的Counterdefaultdict 结合使用。

    顾名思义,计数器计数相同的元素,而 defaultdict 允许您通过提供默认值(在本例中为空的 Counter)来访问不存在的键。然后你的代码就变成了

    from collections import Counter, defaultdict
    
    
    d = defaultdict(Counter)
    d['siteA'] = Counter({'00000000': 3, '11111111': 4, '22222222': 5})
    d['siteB'] = Counter({'00000000': 1, '11111111': 2, '22222222': 5})
    print(d.items())
    
    > dict_items([('siteA', Counter({'22222222': 5, '11111111': 4, '00000000': 3})), 
    >             ('siteB', Counter({'22222222': 5, '11111111': 2, '00000000': 1}))])
    
    # d + e:
    d['siteA'].update({'00000000': 5})
    print(d.items())
    
    > dict_items([('siteA', Counter({'00000000': 8, '22222222': 5, '11111111': 4})), 
    >             ('siteB', Counter({'22222222': 5, '11111111': 2, '00000000': 1}))])
    
    # d + f
    d['siteB'].update({'33333333': 10})
    print(d.items())
    
    > dict_items([('siteA', Counter({'00000000': 8, '22222222': 5, '11111111': 4})), 
    >             ('siteB', Counter({'33333333': 10, '22222222': 5, '11111111': 2, '00000000': 1}))])
    
    # d + g
    d['siteC'].update({'00000000': 8})
    print(d.items())
    
    > dict_items([('siteA', Counter({'00000000': 8, '22222222': 5, '11111111': 4})), 
    >             ('siteB', Counter({'33333333': 10, '22222222': 5, '11111111': 2, '00000000': 1})), 
    >.            ('siteC', Counter({'00000000': 8}))])
    

    【讨论】:

      【解决方案3】:

      鉴于您的字典 dict[site][address] 的格式,假设这个合并函数将从 dictFrom 中获取值并根据您的规则将它们插入到 dictTo 中。

      def merge(dictTo, dictFrom):
          for site in dictFrom:
              if site not in dictTo:
                  dictTo[site] = {}
      
              for address in dictFrom[site]:
                  dictTo[site][address] = dictTo[site].get(address, 0) + dictFrom[site][address]
      
      merge(d, e)
      merge(d, f)
      merge(d, g)
      

      这可能比 jpp 的答案更可取,因为 dict[site] 上的对象仍然是基本的 dicts。

      【讨论】:

      • 那个basic dicts有什么好处? Counter 是 jpp 提到的 dict 的子类。
      • 我认为保持与问题中的类型相同就足以让我认为这是值得的。但是,您可以在 jpp 的输出计数器的打印中看到默认情况下打印为 Counter({... 而不是 {...,我认为这更好。此外,如果我试图做的只是捍卫我的答案,那么我会说使用函数比编写相同的循环三次更可取。
      • 另外,我忘了说这个方法不需要你像jpp那样一开始就转换你的数据。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-22
      • 2018-07-17
      • 2018-09-19
      • 2017-02-16
      • 1970-01-01
      • 2022-11-21
      相关资源
      最近更新 更多