答案 0 :(得分:43)
这是一个双向dict
的类,受Finding key from value in Python dictionary启发并修改为允许以下2)和3)。
请注意:
bd.inverse
被修改时,逆目录 bd
会自动更新。bd.inverse[value]
始终是key
的列表,bd[key] == value
。bidict
模块不同,此处我们可以有2个具有相同值的键,这是非常重要的。<强>代码:强>
class bidict(dict):
def __init__(self, *args, **kwargs):
super(bidict, self).__init__(*args, **kwargs)
self.inverse = {}
for key, value in self.items():
self.inverse.setdefault(value,[]).append(key)
def __setitem__(self, key, value):
if key in self:
self.inverse[self[key]].remove(key)
super(bidict, self).__setitem__(key, value)
self.inverse.setdefault(value,[]).append(key)
def __delitem__(self, key):
self.inverse.setdefault(self[key],[]).remove(key)
if self[key] in self.inverse and not self.inverse[self[key]]:
del self.inverse[self[key]]
super(bidict, self).__delitem__(key)
用法示例:
bd = bidict({'a': 1, 'b': 2})
print(bd) # {'a': 1, 'b': 2}
print(bd.inverse) # {1: ['a'], 2: ['b']}
bd['c'] = 1 # Now two keys have the same value (= 1)
print(bd) # {'a': 1, 'c': 1, 'b': 2}
print(bd.inverse) # {1: ['a', 'c'], 2: ['b']}
del bd['c']
print(bd) # {'a': 1, 'b': 2}
print(bd.inverse) # {1: ['a'], 2: ['b']}
del bd['a']
print(bd) # {'b': 2}
print(bd.inverse) # {2: ['b']}
bd['b'] = 3
print(bd) # {'b': 3}
print(bd.inverse) # {2: [], 3: ['b']}
答案 1 :(得分:33)
答案 2 :(得分:31)
答案 3 :(得分:2)
下面的代码片段实现了一个可逆(双射)地图:
class BijectionError(Exception):
"""Must set a unique value in a BijectiveMap."""
def __init__(self, value):
self.value = value
msg = 'The value "{}" is already in the mapping.'
super().__init__(msg.format(value))
class BijectiveMap(dict):
"""Invertible map."""
def __init__(self, inverse=None):
if inverse is None:
inverse = self.__class__(inverse=self)
self.inverse = inverse
def __setitem__(self, key, value):
if value in self.inverse:
raise BijectionError(value)
self.inverse._set_item(value, key)
self._set_item(key, value)
def __delitem__(self, key):
self.inverse._del_item(self[key])
self._del_item(key)
def _del_item(self, key):
super().__delitem__(key)
def _set_item(self, key, value):
super().__setitem__(key, value)
此实现的优势在于inverse
的{{1}}属性又是BijectiveMap
。因此,您可以执行以下操作:
BijectiveMap
答案 4 :(得分:1)
答案 5 :(得分:1)
不幸的是,评分最高的答案bidict
无效。
共有三个选项:
子类字典:您可以创建dict
的子类,但请注意。您需要编写update
,pop
,initializer
,setdefault
的自定义实现。 dict
实现不调用__setitem__
。这就是评分最高的答案存在问题的原因。
从UserDict继承:这就像一个字典,不同之处在于所有例程都可以正确调用。它在幕后data
中使用字典。您可以阅读Python Documentation或use a simple implementation of a by directional list that works in Python 3。抱歉,没有逐字记录:我不确定其版权。
从抽象基类继承:从collections.abc继承将帮助您获得新类的所有正确协议和实现。除非它也可以加密并缓存到数据库,否则这对于双向字典来说是多余的。
TL; DR-使用this作为代码。阅读Trey Hunner的article了解详情。
答案 6 :(得分:0)
首先,您必须确保值映射的键是一对一的,否则,无法构建双向映射。
第二,数据集有多大?如果没有太多数据,只需使用2个单独的地图,并在更新时更新它们。或者更好的是,使用现有的解决方案,如Bidict,它只是2个dicts的包装,内置更新/删除。
但是如果数据集很大,并且不希望保持2个dicts:
如果键和值都是数字,请考虑使用的可能性 插值以近似映射。如果是绝大多数的 映射函数(及其中)可以覆盖键值对 反向功能),那么你只需要在地图中记录异常值。
如果大部分访问都是单向的(key-&gt; value),那么它就是完全的
好的是逐步建立反向地图,交换时间为
空间。
代码:
d = {1: "one", 2: "two" }
reverse = {}
def get_key_by_value(v):
if v not in reverse:
for _k, _v in d.items():
if _v == v:
reverse[_v] = _k
break
return reverse[v]