【问题标题】:How to check multiple dictionaries for a value, change any/all if condition is met如何检查多个字典的值,如果满足条件则更改任何/全部
【发布时间】:2019-03-13 08:05:45
【问题描述】:

我有一些共享键的字典,例如

dict1 = {'a' : 1, 'b' : 2, 'c' : -1}
dict2 = {'a' : -1, 'b' : -3, 'c' : 3}

我想对两者都执行条件操作,但只更改满足条件的键的值。例如,我想将 10 添加到任何具有负值的键“b”,这将产生:

dict1 = {'a' : 1, 'b' : 2, 'c' : -1}
dict2 = {'a' : -1, 'b' : 7, 'c' : 3}

有没有办法循环遍历字典共有的“键”并且只对这些键进行操作?例如

dicts = [dict1, dict2]

for i in dicts:
    if i['b'] < 0:
        i['b'] = i['b'] + 10

但这会产生以下有趣的结果:

print dicts[0]
print dicts[1]

{'a': 1, 'c': -1, 'b': 12}
{'a': -1, 'c': 3, 'b': -3}

我不确定我是否理解。

我有很多 (1000s) 对这种结构在循环中生成,所以如果可能的话,我希望它相当高效。

谢谢!

编辑:

公认的解决方案

for key in set(dict1).intersection(set(dict2)):
  for i in dicts:
    if i[key] < 0:
      i[key] = i[key] + 10

非常适合 2 个字典。但是,如果我最初有所有相似的“n”个字典,例如对于 4 个字典:

dict1 = {'a' : 1, 'b' : 2, 'c' : -1}
dict2 = {'a' : -1, 'b' : -3, 'c' : 3}
dict3 = {'a' : 1, 'b': -1, 'c' : -4}
dict4 = {'a' : 0, 'b': 5, 'c' : 2}

dicts = [dict1, dict2, dict3, dict4]

而期望的结果(仅将 10 加到所有否定的 'b' 上)将是:

dict1 = {'a' : 1, 'b' : 2, 'c' : -1}
dict2 = {'a' : -1, 'b' : 7, 'c' : 3}
dict3 = {'a' : 1, 'b': 9, 'c' : -4}
dict4 = {'a' : 0, 'b': 5, 'c' : 2}

同样的循环结构是否仍然适用?

【问题讨论】:

  • 我无法重现您所看到的内容(在 Python 3 上),我只看到第二个字典发生了变化,这正是您想要的。
  • 无法在 Python 2.7 或 3.4.5 下重现您的问题
  • 这是 Jupyter Notebook 中的 Python 2.7,无法解释为什么您没有看到我所看到的...
  • 虽然您的代码确实像其他人所说的那样工作,但这不是您应该这样做的方式。如果你现在改变 i 然后 dict2 也会改变,他们是同一个字典

标签: python dictionary if-statement conditional


【解决方案1】:

我无法重现您的问题。但是由于您问题的第二部分考虑了效率,我建议您尝试字典理解。该算法仍然具有 O(n) 复杂度,但循环构造的实现效率更高:

def num_changer(d, inc=10, k='b'):
    return {k: v if (k != 'b') or (v >= 0) else v + 10 for k, v in d.items()}

dict1 = num_changer(dict1)
dict2 = num_changer(dict2)

print(dict1, dict2, sep='\n')

{'a': 1, 'b': 2, 'c': -1}
{'a': -1, 'b': 7, 'c': 3}

【讨论】:

    【解决方案2】:

    您可以动态创建包含相交键的字典。

    for a in set([x for x in dict1 if x in dict2]):
        if dict1[a] < 0: dict1[a] += 10
        if dict2[a] < 0: dict2[a] += 10
    
    
    >>> dict1
    {'a': 1, 'c': 9, 'b': 2}
    >>> dict2
    {'a': 9, 'c': 3, 'b': 7}
    >>> 
    

    但是,对于许多 dicts,您应该以更易读的方式执行此操作

    【讨论】:

      【解决方案3】:

      我无法在 Python 3 中重现您的问题。我建议您使用 set()intersection() 来收集公用密钥:

      dict1 = {'a' : 1, 'b' : 2, 'c' : -1}
      dict2 = {'d' : -1, 'b' : -3, 'e' : 3}
      
      dicts = [dict1, dict2]
      
      for key in set(dict1).intersection(set(dict2)):
        for i in dicts:
          if i[key] < 0:
            i[key] = i[key] + 10
      

      产量:

      {'a': 1, 'b': 2, 'c': -1}
      {'d': -1, 'b': 7, 'e': 3}
      

      【讨论】:

      • 是的,这很好用,谢谢!当计时器用完时,我会接受它作为答案。另外一个问题,我的键已重新排列,'b' 位于末尾,这是预期的吗?
      • Python 中的标准字典没有排序,这与 OrderedDict() 相对,后者会记住插入顺序。这里有一个很好的概述:stackoverflow.com/q/25056387/8146556
      • 感谢您的参考。如果 dicts = [dict1, dict2, dict3, dict4] 的所有字典大小相同并共享公共键,您的答案将如何变化?
      • IIUC,如果您所有的字典都包含相同的一组键,那么您可以将第一个 for 循环修改为for key in dict1.keys()
      • 谢谢,为了清楚起见,我将在我的初始帖子中添加一个扩展名,以检查我是否正确询问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 1970-01-01
      • 2017-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多