例如,我有两个词:
Dict A: {'a': 1, 'b': 2, 'c': 3}
Dict B: {'b': 3, 'c': 4, 'd': 5}
我需要一种“结合”两个dicts的pythonic方式,结果是:
{'a': 1, 'b': 5, 'c': 7, 'd': 5}
也就是说:如果一个键出现在两个词组中,添加它们的值,如果它只出现在一个词典中,则保持其值。
答案 0 :(得分:807)
>>> from collections import Counter
>>> A = Counter({'a':1, 'b':2, 'c':3})
>>> B = Counter({'b':3, 'c':4, 'd':5})
>>> A + B
Counter({'c': 7, 'b': 5, 'd': 5, 'a': 1})
计数器基本上是dict
的子类,因此您仍然可以使用它们执行其他所有操作,例如迭代其键和值。
答案 1 :(得分:115)
更通用的解决方案,也适用于非数字值:
a = {'a': 'foo', 'b':'bar', 'c': 'baz'}
b = {'a': 'spam', 'c':'ham', 'x': 'blah'}
r = dict(a.items() + b.items() +
[(k, a[k] + b[k]) for k in set(b) & set(a)])
甚至更通用:
def combine_dicts(a, b, op=operator.add):
return dict(a.items() + b.items() +
[(k, op(a[k], b[k])) for k in set(b) & set(a)])
例如:
>>> a = {'a': 2, 'b':3, 'c':4}
>>> b = {'a': 5, 'c':6, 'x':7}
>>> import operator
>>> print combine_dicts(a, b, operator.mul)
{'a': 10, 'x': 7, 'c': 24, 'b': 3}
答案 2 :(得分:64)
>>> A = {'a':1, 'b':2, 'c':3}
>>> B = {'b':3, 'c':4, 'd':5}
>>> c = {x: A.get(x, 0) + B.get(x, 0) for x in set(A).union(B)}
>>> print(c)
{'a': 1, 'c': 7, 'b': 5, 'd': 5}
答案 3 :(得分:45)
<强>说明:强> 有(可能)最好的解决方案。但你必须知道并记住它,有时候你不得不希望你的Python版本不是太老或者问题可能是什么。
然后有最“愚蠢”的解决方案。它们很棒而且很短,但有时很难理解,阅读和记忆。
但是,有一种方法可以尝试重新发明轮子。 - 为什么重新发明轮子? - 通常因为它是一种非常好的学习方式(有时仅仅因为已经存在的工具不能完全按照你想要的方式和/或你想要的方式完成)而且最简单的方法就是你不知道或者不记得问题的完美工具。 所以,我建议从Counter
模块重新发明collections
类的轮子(部分至少):
class MyDict(dict):
def __add__(self, oth):
r = self.copy()
try:
for key, val in oth.items():
if key in r:
r[key] += val # You can custom it here
else:
r[key] = val
except AttributeError: # In case oth isn't a dict
return NotImplemented # The convention when a case isn't handled
return r
a = MyDict({'a':1, 'b':2, 'c':3})
b = MyDict({'b':3, 'c':4, 'd':5})
print(a+b) # Output {'a':1, 'b': 5, 'c': 7, 'd': 5}
可能还有其他方法可以实现这一点,并且已经有工具可以做到这一点,但总是很好地想象事情基本上是如何工作的。
答案 4 :(得分:13)
myDict = {}
for k in itertools.chain(A.keys(), B.keys()):
myDict[k] = A.get(k, 0)+B.get(k, 0)
答案 5 :(得分:12)
没有额外进口的那个!
他们是一个名为EAFP的 pythonic标准(比请求更容易要求宽恕)。下面的代码基于 python标准。
# The A and B dictionaries
A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}
# The final dictionary. Will contain the final outputs.
newdict = {}
# Make sure every key of A and B get into the final dictionary 'newdict'.
newdict.update(A)
newdict.update(B)
# Iterate through each key of A.
for i in A.keys():
# If same key exist on B, its values from A and B will add together and
# get included in the final dictionary 'newdict'.
try:
addition = A[i] + B[i]
newdict[i] = addition
# If current key does not exist in dictionary B, it will give a KeyError,
# catch it and continue looping.
except KeyError:
continue
编辑:感谢jerzyk提出的改进建议。
答案 6 :(得分:10)
import itertools
import collections
dictA = {'a':1, 'b':2, 'c':3}
dictB = {'b':3, 'c':4, 'd':5}
new_dict = collections.defaultdict(int)
# use dict.items() instead of dict.iteritems() for Python3
for k, v in itertools.chain(dictA.iteritems(), dictB.iteritems()):
new_dict[k] += v
print dict(new_dict)
# OUTPUT
{'a': 1, 'c': 7, 'b': 5, 'd': 5}
OR
替代方案,您可以使用Counter,如上面提到的@Martijn。
答案 7 :(得分:10)
绝对总结Counter()
s是在这种情况下最狡猾的方式,但只有当它产生正值。以下是一个示例,您可以看到在c
字典中取消c
的值后,结果中没有B
。
In [1]: from collections import Counter
In [2]: A = Counter({'a':1, 'b':2, 'c':3})
In [3]: B = Counter({'b':3, 'c':-4, 'd':5})
In [4]: A + B
Out[4]: Counter({'d': 5, 'b': 5, 'a': 1})
那是因为Counter
s主要设计为使用正整数来表示运行计数(负计数无意义)。但是为了帮助解决这些用例,python记录了最小范围和类型限制,如下所示:
- Counter类本身就是一本字典 子类,其键和值没有限制。价值观是 意图是代表计数的数字,但你可以存储 价值领域的任何东西。
most_common()
方法仅需要 价值可以订购。- 适用于
c[key]
等就地操作+= 1
,值类型只需要支持加法和减法。因此,分数,浮点数和小数将起作用,负值也是如此 支持的。update()
和subtract()
也是如此 允许输入和输出的负值和零值。- multiset方法仅适用于具有正值的用例。 输入可以是负数或零,但只有正数的输出 值已创建。没有类型限制,但值类型 需要支持加法,减法和比较。
elements()
方法需要整数计数。它忽略了零和负数。
因此,为了在总结计数器后解决该问题,您可以使用Counter.update
来获得所需的输出。它的工作方式与dict.update()
类似,但会添加计数而不是替换它们。
In [24]: A.update(B)
In [25]: A
Out[25]: Counter({'d': 5, 'b': 5, 'a': 1, 'c': -1})
答案 8 :(得分:7)
要获得更通用和可扩展的方式,请检查mergedict。它使用singledispatch
并可以根据其类型合并值。
示例:
from mergedict import MergeDict
class SumDict(MergeDict):
@MergeDict.dispatch(int)
def merge_int(this, other):
return this + other
d2 = SumDict({'a': 1, 'b': 'one'})
d2.merge({'a':2, 'b': 'two'})
assert d2 == {'a': 3, 'b': 'two'}
答案 9 :(得分:4)
感谢@tokeinizer_fsj在评论中告诉我,我没有完全理解问题的意思(我认为添加意味着只添加键,最终在两个dictinaries中有所不同,相反,我的意思公共密钥值应该相加)。所以我在合并之前添加了循环,以便第二个字典包含公共密钥的总和。最后一个字典将是其值将在新字典中持续的字典,这是两者合并的结果,所以我的问题就解决了。该解决方案在python 3.5及以下版本中有效。
a = {
"a": 1,
"b": 2,
"c": 3
}
b = {
"a": 2,
"b": 3,
"d": 5
}
# Python 3.5
for key in b:
if key in a:
b[key] = b[key] + a[key]
c = {**a, **b}
print(c)
>>> c
{'a': 3, 'b': 5, 'c': 3, 'd': 5}
a = {'a': 1, 'b': 2, 'c': 3}
b = {'b': 3, 'c': 4, 'd': 5}
def mergsum(a, b):
for k in b:
if k in a:
b[k] = b[k] + a[k]
c = {**a, **b}
return c
print(mergsum(a, b))
答案 10 :(得分:4)
此外,请注意a.update( b )
比a + b
from collections import Counter
a = Counter({'menu': 20, 'good': 15, 'happy': 10, 'bar': 5})
b = Counter({'menu': 1, 'good': 1, 'bar': 3})
%timeit a + b;
## 100000 loops, best of 3: 8.62 µs per loop
## The slowest run took 4.04 times longer than the fastest. This could mean that an intermediate result is being cached.
%timeit a.update(b)
## 100000 loops, best of 3: 4.51 µs per loop
答案 11 :(得分:2)
这是一个简单的解决方案,用于合并两个字典,其中+=
可以应用于值,它只需要在字典上迭代一次,我很惊讶没有人建议这个
a = {'a':1, 'b':2, 'c':3}
dicts = [{'b':3, 'c':4, 'd':5},
{'c':9, 'a':9, 'd':9}]
def merge_dicts(merged,mergedfrom):
for k,v in mergedfrom.items():
if k in merged:
merged[k] += v
else:
merged[k] = v
return merged
for dct in dicts:
a = merge_dicts(a,dct)
print (a)
#{'c': 16, 'b': 5, 'd': 14, 'a': 10}
答案 12 :(得分:2)
def merge_with(f, xs, ys):
xs = a_copy_of(xs) # dict(xs), maybe generalizable?
for (y, v) in ys.iteritems():
xs[y] = v if y not in xs else f(xs[x], v)
merge_with((lambda x, y: x + y), A, B)
你可以很容易地概括一下:
def merge_dicts(f, *dicts):
result = {}
for d in dicts:
for (k, v) in d.iteritems():
result[k] = v if k not in result else f(result[k], v)
然后它可以采取任何数量的决定。
答案 13 :(得分:2)
将三个词组a,b,c合并为一行而不包含任何其他模块或库
如果我们有三个词组
a = {"a":9}
b = {"b":7}
c = {'b': 2, 'd': 90}
将所有内容合并为一行并使用
返回一个dict对象c = dict(a.items() + b.items() + c.items())
返回
{'a': 9, 'b': 2, 'd': 90}
答案 14 :(得分:1)
此解决方案易于使用,它用作普通字典,但您可以使用sum函数。
class SumDict(dict):
def __add__(self, y):
return {x: self.get(x, 0) + y.get(x, 0) for x in set(self).union(y)}
A = SumDict({'a': 1, 'c': 2})
B = SumDict({'b': 3, 'c': 4}) # Also works: B = {'b': 3, 'c': 4}
print(A + B) # OUTPUT {'a': 1, 'b': 3, 'c': 6}
答案 15 :(得分:0)
上述解决方案非常适合您拥有少量Counter
s的情况。如果你有一个很大的列表,那么这样的东西会更好:
from collections import Counter
A = Counter({'a':1, 'b':2, 'c':3})
B = Counter({'b':3, 'c':4, 'd':5})
C = Counter({'a': 5, 'e':3})
list_of_counts = [A, B, C]
total = sum(list_of_counts, Counter())
print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})
上述解决方案基本上将Counter
s总结为:
total = Counter()
for count in list_of_counts:
total += count
print(total)
# Counter({'c': 7, 'a': 6, 'b': 5, 'd': 5, 'e': 3})
这也是做同样的事情,但我认为看看它在下面有效地做了什么总是有帮助的。
答案 16 :(得分:0)
怎么样:
def dict_merge_and_sum( d1, d2 ):
ret = d1
ret.update({ k:v + d2[k] for k,v in d1.items() if k in d2 })
ret.update({ k:v for k,v in d2.items() if k not in d1 })
return ret
A = {'a': 1, 'b': 2, 'c': 3}
B = {'b': 3, 'c': 4, 'd': 5}
print( dict_merge_and_sum( A, B ) )
输出:
{'d': 5, 'a': 1, 'c': 7, 'b': 5}
答案 17 :(得分:-2)
最好用的是dict():
$subtitles = Subtitles::load('subtitles.srt'); // you can also manually add subtitles from DB using ->add(...) method
$subtitles->shiftTimeGradually(-10);
$subtitles->save('synced-subtitles.srt');