Pythondict是非常有用的数据结构:
d = {'a': 1, 'b': 2}
d['a'] # get 1
有时,您还想按值编制索引。
d[1] # get 'a'
哪个是实现此数据结构的最有效方法?有官方推荐的方法吗?
Pythondict是非常有用的数据结构:
d = {'a': 1, 'b': 2}
d['a'] # get 1
有时,您还想按值编制索引。
d[1] # get 'a'
哪个是实现此数据结构的最有效方法?有官方推荐的方法吗?
{1: ['a', 'A'], 2: 'b'}。请参阅我的答案以了解这种方法。
                Answers:
这是一个双向类,其dict灵感来自于从Python字典中的值中查找键,并进行了修改以允许以下2)和3)。
注意 :
bd.inverse自动更新bd。bd.inverse[value]始终是一个列表的key,使得bd[key] == value。bidict模块不同,这里我们可以有两个具有相同值的键,这非常重要。码:
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']}
self[key]in的重复查找,__delitem__()并value = self[key]为此类查找重新使用单个分配。但是...是的。可以忽略不计。感谢您的真棒,Basj!
                    您可以通过相反的顺序添加键值对来使用相同的字典本身。
d = {'a':1,'b':2}
revd = dict([d.items()中i的反向(i)])
d.update(revd)
    d.update( dict((d[k], k) for k in d) )。
                    dict((v, k) for (k, v) in d.items())。在任何情况下,你可以直接传递对来.update: d.update(reversed(i) for i in d.items())。
                    d={'a':1, 'b':2, 1: 'b'}
                    dict(map(reversed, a_dict.items()))。
                    d.update(revd)因此效果很好,因此我仍在考虑投票。让我们考虑一下。
                    下面的代码片段实现了一个可逆(双射)映射:
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)
此实现的优点是inversea的属性BijectiveMap再次是a BijectiveMap。因此,您可以执行以下操作:
>>> foo = BijectiveMap()
>>> foo['steve'] = 42
>>> foo.inverse
{42: 'steve'}
>>> foo.inverse.inverse
{'steve': 42}
>>> foo.inverse.inverse is foo
True
可能是这样的:
import itertools
class BidirDict(dict):
    def __init__(self, iterable=(), **kwargs):
        self.update(iterable, **kwargs)
    def update(self, iterable=(), **kwargs):
        if hasattr(iterable, 'iteritems'):
            iterable = iterable.iteritems()
        for (key, value) in itertools.chain(iterable, kwargs.iteritems()):
            self[key] = value
    def __setitem__(self, key, value):
        if key in self:
            del self[key]
        if value in self:
            del self[value]
        dict.__setitem__(self, key, value)
        dict.__setitem__(self, value, key)
    def __delitem__(self, key):
        value = self[key]
        dict.__delitem__(self, key)
        dict.__delitem__(self, value)
    def __repr__(self):
        return '%s(%s)' % (type(self).__name__, dict.__repr__(self))
如果多个键具有给定的值,则必须决定要发生什么。给定对的双向性很容易被后来插入的一对消灭。我实现了一个可能的选择。
范例:
bd = BidirDict({'a': 'myvalue1', 'b': 'myvalue2', 'c': 'myvalue2'})
print bd['myvalue1']   # a
print bd['myvalue2']   # b        
dict([('a', 'b'), ('b', 'c')]); dict['b']->'c'而不是键'a'。
                    print bd['myvalue2']回答b, c(或[b, c],或(b, c),或其他任何问题)?
                    首先,您必须确保值映射的关键是一对一的,否则,将无法构建双向映射。
第二,数据集有多大?如果没有太多数据,则仅使用2个单独的地图,并在更新时同时更新两个地图。或者更好的方法是使用现有的解决方案(例如Bidict),该解决方案仅包含2个字典,并内置更新/删除功能。
但是,如果数据集很大,则不希望保留2个字典:
如果键和值都是数字,请考虑使用插值法近似映射的可能性。如果映射功能(及其
反向功能)可以覆盖绝大多数键值对,那么您只需要在地图中记录离群值即可。
如果大多数访问是单向的(键-值),则完全可以逐步构建反向映射,以时间换取
空间。
码:
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]
不幸的是,最高评分的答案bidict无效。
共有三个选项:
子类字典:您可以创建的子类dict,但要小心。你需要写的自定义实现update,pop,initializer,setdefault。该dict实现不叫__setitem__。这就是为什么评分最高的答案存在问题。
从UserDict继承:就像dict一样,不同之处在于所有例程都可以正确调用。它在幕后使用了一个dict,称为data。您可以阅读Python文档,或使用在Python 3中可以使用的按方向列表的简单实现。很抱歉没有一字不漏地包含它:我不确定它的版权。
从抽象基类继承:从collections.abc继承将帮助您获得新类的所有正确协议和实现。除非双向字典也可以加密并缓存到数据库,否则这是过分的。
TL; DR-将其用于您的代码。阅读 Trey Hunner的文章以了解详细信息。