双向/反向地图

我在python中做这个交换机的事情,我需要跟踪谁跟谁交谈,所以如果Alice – > Bob,那么这意味着Bob – > Alice。

是的,我可以填充两个哈希映射,但我想知道是否有人有一个想法做一个。

或者build议另一个数据结构。

没有多个对话。 假设这是一个客户服务呼叫中心,所以当Alice拨入交换台时,她只会和Bob通话。 他的答复也仅限于她。

你可以创build自己的字典types,通过子类的dict和添加你想要的逻辑。 这是一个基本的例子:

 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 

它的工作原理是这样的:

 >>> 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' 

我相信我没有涵盖所有的情况,但这应该让你开始。

在你的特殊情况下,你可以将它们存储在一个字典中:

 relation = {} relation['Alice'] = 'Bob' relation['Bob'] = 'Alice' 

因为你所描述的是一个对称关系。 A -> B => B -> A

我只是填充第二个哈希值

 reverse_map = dict((reversed(item) for item in forward_map.items())) 

假设您可以节省内存,两个哈希映射实际上可能是性能最快的解决scheme。 我会把它们包装在一个类中 – 程序员的负担是确保两个哈希映射正确同步。

你有两个单独的问题。

  1. 你有一个“对话”对象。 它是指两个人。 由于一个人可以有多个对话,你有一个多对多的关系。

  2. 您有一个从人员地图到对话列表。 转换将有一对人员。

做这样的事情

 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 ) 

不,如果不制作两本字典,就没有办法做到这一点。 如何用一本词典来实现这一点,同时继续提供可比较的性能?

你最好创build一个封装两个字典的自定义types,并公开你想要的function。

这是一个简单的双向字典实现 ,虽然我不知道它是否会满足您的性能要求。

(从这篇关于增强Bimap for Python的博客文章中获得了一些关于该主题的讨论。)

您可以使用Python Cookbook上的配方578224中所示的DoubleDict

另一个可能的解决scheme是实现一个dict的子类,它保存原始字典并跟踪它的反转版本。 如果键和值重叠,保持两个独立的字典是有用的。

 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. 

例:

 >>> 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'} 

kjbuckets C扩展模块提供了一个“graphics”数据结构,我相信给你你想要的。

pypi上有集合扩展库: https ://pypi.python.org/pypi/collections-extended/0.6.0

使用双射类很简单:

 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