【问题标题】:If keys of two dictionaries are equal, perform operation using both values and move to new dict (python)如果两个字典的键相等,则使用两个值执行操作并移动到新字典(python)
【发布时间】:2017-11-22 05:49:55
【问题描述】:

我有两个字典,像这样:

d1 = {'red':10, 'blue':20, 'green':30, 'yellow':40}
d2 = {'red':1, 'blue':2, 'green':3}

我想遍历 d1 中的每个项目,看看键是否与 d2 中的键匹配。如果是这样,我想从 d1 键中减去 d2 键,并将新的键/值对移动到新字典中,结果是:

d3 = {'red':9, 'blue':18, 'green':27, 'yellow':40}

我为此编写了以下脚本:

for x, y in d1.items():
    for a, b in d2.items():
        if x == a:
            d3[x] = (y-b)
        elif x not in d2.items():
            d3[x] = y

这可行,但是当我尝试在包含数千个项目的两个字典上使用它时,该函数永远不会完成。我想这太慢了。

您能推荐一个更好的方法吗?非常感谢。

【问题讨论】:

  • 您不需要遍历d2。您可以在d2 中查找x。这就是字典的用途。
  • 你能举例说明你的意思吗?我想了解这一点。

标签: python loops dictionary compare


【解决方案1】:

是的,你把事情弄得太复杂了,简单地使用字典理解:

{k:v1-d2.get(k,0) for k,v1 in d1.items()}

这将生成:

>>> {k:v1-d2.get(k,0) for k,v1 in d1.items()}
{'red': 9, 'blue': 18, 'green': 27, 'yellow': 40}

代码的工作方式如下:字典解析将遍历d1 的items(),其中k 是键,v1 是与d1 关联的d1 的值。

然后对于每个这样的键值对,我们将v1-d2.get(k,0) 与结果字典中的键k 相关联。 d2.get(k,0) 将旨在获取与k 关联的值,如果键在字典中不,它将返回0。

算法运行 - 给定的字典查找可能发生在 O(1) 中(不保证,但很有可能) - 在 O(n) 和 n d1 中的元素数量,相当快。

【讨论】:

  • 谢谢,这是有道理的...当您说“与k1 相关联”时,您的意思是“与k 相关联”,因为没有k1代码?
  • @ddrsee:是的,很抱歉造成混乱。
  • 没问题,谢谢您的帮助。如果您有一个最喜欢的网页来学习听写理解,请不要犹豫,分享它! :-)
  • @ddrsee:更新了对 SO 上有关字典理解的文档的参考。
  • 非常感谢。
【解决方案2】:

您可以将 dict 理解与 if-else 语句一起使用:

d1 = {'red':10, 'blue':20, 'green':30, 'yellow':40}
d2 = {'red':1, 'blue':2, 'green':3}

new_dict = {a:b-d2[a] if a in d2 else b for a, b in d1.items()}

输出:

{'blue': 18, 'green': 27, 'red': 9, 'yellow': 40}

【讨论】:

    【解决方案3】:

    仅作记录(因为我发现 字典理解 非常优雅)您也可以使用 collections.Counter(这也很简洁)来完成这项任务:

    In [1]: from collections import Counter
    
    In [2]: d1 = {'red':10, 'blue':20, 'green':30, 'yellow':40}
       ...: d2 = {'red':1, 'blue':2, 'green':3}
       ...: 
    
    In [3]: A = Counter(d1)
    
    In [4]: B = Counter(d2)
    
    In [5]: A - B
    Out[5]: Counter({'blue': 18, 'green': 27, 'red': 9, 'yellow': 40})
    

    正如@WillemVanOnsem 在 cmets 中指出的那样,

    "如果 d2 中的某个值高于 d1 中对应的值,我们将 没有得到负数,但是key会消失:一个计数器 通常假设计数是自然数”。

    但是,还有另一种解决方案依赖于 Counter,使用其 substract() 方法(仅在 python 3.2 中引入),但它会修改您的 Counter 对象之一(因为它的行为作为dict.update():

    In [26]: A = Counter({'red':10, 'blue':20, 'green':30, 'yellow':40})
        ...: B = Counter({'red':1, 'blue':30, 'green':3})
        ...: 
    
    In [27]: A - B # The 'blue' key disappear 
    Out[27]: Counter({'green': 27, 'red': 9, 'yellow': 40})
    
    In [28]: A.subtract(B) # It handles negative values ...
    
    In [29]: A # ...but modify the counter A
    Out[29]: Counter({'blue': -10, 'green': 27, 'red': 9, 'yellow': 40})
    

    collections.Counter 的主要目的是计算/存储可散列对象的出现次数(因此假设计数是自然数),但它基本上是 dict 的子类,它提供了组合 Counter 对象的多种操作它们之间(加法、减法、并集和交集)。

    【讨论】:

    • 如果d2中的值高于d1中对应的值,我们将不会获得负数,但是key会消失:通常是一个计数器假定计数是自然数。
    • @WillemVanOnsem 很好,谢谢!我将针对这种情况使用适当的方法进行更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    相关资源
    最近更新 更多