如何在Python字典上执行set操作?

snt*_*nth 4 python dictionary

虽然能够在字典的键之间进行设置操作是非常有用的,但我经常希望我可以对字典本身执行设置操作.

我找到了一些用于区分两个词典的方法,但我发现那些词语非常冗长,并且觉得必须有更多的pythonic答案.

snt*_*nth 6

TL;博士食谱:{k:d1.get(k, k in d1 or d2[k]) for k in set(d1) | set(d2)}|可以与任何其他集合运算符来代替.

根据@ torek的评论,另一个可能更容易记住的配方(虽然完全一般)是:{k:d1.get(k,d2.get(k)) for k in set(d1) | set(d2)}.

完整答案如下:

我的第一个答案没有正确处理评估为False的值.这是一个处理Falsey值的改进版本:

>>> d1 = {'one':1, 'both':3, 'falsey_one':False, 'falsey_both':None}
>>> d2 = {'two':2, 'both':30, 'falsey_two':None, 'falsey_both':False}
>>> 
>>> print "d1 - d2:", {k:d1[k] for k in d1 if k not in d2}                  # 0
d1 - d2: {'falsey_one': False, 'one': 1}
>>> print "d2 - d1:", {k:d2[k] for k in d2 if k not in d1}                  # 1
d2 - d1: {'falsey_two': None, 'two': 2}
>>> print "intersection:", {k:d1[k] for k in d1 if k in d2}                      # 2
intersection: {'both': 3, 'falsey_both': None}
>>> print "union:", {k:d1.get(k, k in d1 or d2[k]) for k in set(d1) | set(d2)}   # 3
union: {'falsey_one': False, 'falsey_both': None, 'both': 3, 'two': 2, 'one': 1, 'falsey_two': None}
Run Code Online (Sandbox Code Playgroud)

版本union是最通用的,可以变成一个函数:

>>> def dict_ops(d1, d2, setop):
...     """Apply set operation `setop` to dictionaries d1 and d2
... 
...     Note: In cases where values are present in both d1 and d2, the value from
...     d1 will be used.
...     """
...     return {k:d1.get(k,k in d1 or d2[k]) for k in setop(set(d1), set(d2))}
... 
>>> print "d1 - d2:", dict_ops(d1, d2, lambda x,y: x-y)
d1 - d2: {'falsey_one': False, 'one': 1}
>>> print "d2 - d1:", dict_ops(d1, d2, lambda x,y: y-x)
d2 - d1: {'falsey_two': None, 'two': 2}
>>> import operator as op
>>> print "intersection:", dict_ops(d1, d2, op.and_)
intersection: {'both': 3, 'falsey_both': None}
>>> print "union:", dict_ops(d1, d2, op.or_)
union: {'falsey_one': False, 'falsey_both': None, 'both': 3, 'two': 2, 'one': 1, 'falsey_two': None}
Run Code Online (Sandbox Code Playgroud)

如果项目都在两个词典中,d1则将使用值.当然,我们可以d2通过改变函数参数的顺序来返回值.

>>> print "union:", dict_ops(d2, d1, op.or_)
union: {'both': 30, 'falsey_two': None, 'falsey_one': False, 'two': 2, 'one': 1, 'falsey_both': False}
Run Code Online (Sandbox Code Playgroud)