将多个映射组合成单个映射

多个字典或映射,希望在逻辑上将它们组合成单个映射以执行某些操作,例如查找值或检查键是否存在。
假如现在有两个字典对象a,b。

a = {'x': 1, 'z': 3}
b = {'y': 2, 'z': 4}

假如现在要检查某一键是否在其中一个字典对象中存在。首先检查a,若a中不存在,则检查b。可以使用collections模块的ChainMap类,如下:

from collections import ChainMap
c = ChainMap(a, b)
print(c['x'])   # Outputs 1 (from a)
print(c['y'])   # Outputs 2 (from b)
print(c['z'])   # Outputs 3 (from a)

ChainMap采用多个映射并使它们在逻辑上显示为一个映射。 但是,映射并不是字面上合并在一起的。 相反,ChainMap保留一个底层映射的列表,并重新定义常用字典操作以扫描列表。 大多数操作都可以:

>>> len(c)
3
>>> list(c.keys())
['x', 'y', 'z']
>>> list(c.values())
[1, 2, 3]
>>>

如果有重复的键,则ChainMap对象实例只会获取第一个字典的键对应的值。因为'z'在a和b中都有出现,但获取c['z']时,得到的只会是3,而不是4。

修改ChainMap对象的操作只会影响到其第一个字典中的相关数据。如下:

>>> c['z'] = 10
>>> c['w'] = 40
>>> del c['x']
>>> a
{'w': 40, 'z': 10}
>>> del c['y']
Traceback (most recent call last):
...
KeyError: "Key not found in the first mapping: 'y'"
>>>

当使用范围值(例如编程语言中的变量(即全局,本地等))时,ChainMap特别有用。 事实上,有一些方法可以简化:

>>> values = ChainMap()
>>> values['x'] = 1
>>> # Add a new mapping
>>> values = values.new_child() 
>>> values['x'] = 2
>>> # Add a new mapping
>>> values = values.new_child()
>>> values['x'] = 3
>>> values
ChainMap({'x': 3}, {'x': 2}, {'x': 1}) 
>>> values['x']
3
>>> # Discard last mapping
>>> values = values.parents
>>> values['x']
2
>>> # Discard last mapping
>>> values = values.parents
>>> values['x']
1
>>> values
ChainMap({'x': 1})
>>>

作为ChainMap的替代方法,可以考虑使用update()方法将字典合并在一起。 例如:

>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> merged = dict(b)
>>> merged.update(a)
>>> merged['x']
1
>>> merged['y']
2
>>> merged['z']
3
>>>

这通常可以实现,但该方案需要创建一个单独的字典对象,或破坏性的改变已存在的字典对象。而且,如果其中原有的字典对象被修改,这种修改并不会反映到合并后的对象,即合并的对象是新的对象,和原有的a或b没有关联。

>>> a['x'] = 13
>>> merged['x']
1

ChainMap使用原始字典,因此它没有此现象。

>>> a = {'x': 1, 'z': 3 } 
>>> b = {'y': 2, 'z': 4 } 
>>> merged = ChainMap(a, b) 
>>> merged['x']
1
>>> a['x'] = 42 
>>> merged['x']    # Notice change to merged dicts
42
>>>

猜你喜欢

转载自www.cnblogs.com/jeffrey-yang/p/11318197.html
今日推荐