Two way/reverse map
我在python中做这个交换台的工作,我需要跟踪谁在和谁说话,所以如果alice——>bob,那么这意味着bob——>alice。
是的,我可以填充两个散列图,但是我想知道是否有人想用一个散列图来填充。
或者建议其他数据结构。
没有多个对话。假设这是一个客户服务呼叫中心,所以当爱丽丝拨电话总机时,她只想和鲍勃通话。他的回答也只针对她。
您可以通过对
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class TwoWayDict(dict): def __setitem__(self, key, value): # Remove any previous connections with these values 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): dict.__delitem__(self, self[key]) dict.__delitem__(self, key) def __len__(self): """Returns the number of connections""" return dict.__len__(self) // 2 |
它的工作原理是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> d = TwoWayDict() >>> d['foo'] = 'bar' >>> d['foo'] 'bar' >>> d['bar'] 'foo' >>> len(d) 1 >>> del d['foo'] >>> d['bar'] Traceback (most recent call last): File"<stdin>", line 7, in <module> KeyError: 'bar' |
我肯定我没有把所有的案子都办妥,但这应该能让你开始。
在您的特殊情况下,您可以将这两个存储在一个字典中:
1 2 3 | relation = {} relation['Alice'] = 'Bob' relation['Bob'] = 'Alice' |
因为你所描述的是对称关系。
我只需要填充第二个哈希,
1 | reverse_map = dict((reversed(item) for item in forward_map.items())) |
我知道这是一个古老的问题,但我想提一下这个问题的另一个很好的解决方案,即python包bidict。它的使用非常直接:
1 2 3 4 | from bidict import bidict map = bidict(Bob ="Alice") print(map["Bob"]) print(map.inv["Alice"]) |
假设您可以节省内存,两个哈希图实际上可能是执行速度最快的解决方案。我将把它们包装在一个类中——程序员的负担是确保两个散列映射正确同步。
你有两个不同的问题。
你有一个"对话"对象。指两个人。因为一个人可以有多个对话,所以你有多对多的关系。
你有一张从人到对话列表的地图。转化会有一对人。
像这样做
1 2 3 4 5 6 7 8 9 | from collections import defaultdict switchboard= defaultdict( list ) x = Conversation("Alice","Bob" ) y = Conversation("Alice","Charlie" ) for c in ( x, y ): switchboard[c.p1].append( c ) switchboard[c.p2].append( c ) |
不,如果不创建两个字典,就真的没有办法做到这一点。在继续提供可比较的性能的同时,如何只使用一个字典来实现这一点呢?
最好创建一个封装两个字典并公开所需功能的自定义类型。
我喜欢其中一条评论中的投标建议。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # This normalization method should save hugely as aDaD ~ yXyX have the same form of smallest grammar. # To get back to your grammar's alphabet use trans def normalize_string(s, nv=None): if nv is None: nv = ord('a') trans = bidict() r = '' for c in s: if c not in trans.inverse: a = chr(nv) nv += 1 trans[a] = c else: a = trans.inverse[c] r += a return r, trans def translate_string(s, trans): res = '' for c in s: res += trans[c] return res if __name__ =="__main__": s ="bnhnbiodfjos" n, tr = normalize_string(s) print(n) print(tr) print(translate_string(n, tr)) |
因为没有太多的文件。但我已经拥有了它所需要的所有功能,可以正常工作。
印刷品:1 2 3 | abcbadefghei bidict({'a': 'b', 'b': 'n', 'c': 'h', 'd': 'i', 'e': 'o', 'f': 'd', 'g': 'f', 'h': 'j', 'i': 's'}) bnhnbiodfjos |
pypi上有collections扩展库:https://pypi.python.org/pypi/collections extended/0.6.0
使用双射类非常简单:
1 2 3 4 5 6 7 8 9 | RESPONSE_TYPES = bijection({ 0x03 : 'module_info', 0x09 : 'network_status_response', 0x10 : 'trust_center_device_update' }) >>> RESPONSE_TYPES[0x03] 'module_info' >>> RESPONSE_TYPES.inverse['network_status_response'] 0x09 |
另一种可能的解决方案是实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class TwoWayDict(dict): def __init__(self, my_dict): dict.__init__(self, my_dict) self.rev_dict = {v : k for k,v in my_dict.iteritems()} def __setitem__(self, key, value): dict.__setitem__(self, key, value) self.rev_dict.__setitem__(value, key) def pop(self, key): self.rev_dict.pop(self[key]) dict.pop(self, key) # The above is just an idea other methods # should also be overridden. |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | >>> d = {'a' : 1, 'b' : 2} # suppose we need to use d and its reversed version >>> twd = TwoWayDict(d) # create a two-way dict >>> twd {'a': 1, 'b': 2} >>> twd.rev_dict {1: 'a', 2: 'b'} >>> twd['a'] 1 >>> twd.rev_dict[2] 'b' >>> twd['c'] = 3 # we add to twd and reversed version also changes >>> twd {'a': 1, 'c': 3, 'b': 2} >>> twd.rev_dict {1: 'a', 2: 'b', 3: 'c'} >>> twd.pop('a') # we pop elements from twd and reversed version changes >>> twd {'c': 3, 'b': 2} >>> twd.rev_dict {2: 'b', 3: 'c'} |
您可以使用一个
下面是一个通过扩展pythons
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class DoubleD(dict): """ Access and delete dictionary elements by key or value.""" def __getitem__(self, key): if key not in self: inv_dict = {v:k for k,v in self.items()} return inv_dict[key] return dict.__getitem__(self, key) def __delitem__(self, key): if key not in self: inv_dict = {v:k for k,v in self.items()} dict.__delitem__(self, inv_dict[key]) else: dict.__delitem__(self, key) |
将其用作普通的python字典,但在构造中除外:
10KJBucketsC扩展模块提供了一个"图形"数据结构,我相信它能提供您想要的东西。