Is there a better way to store a twoway dictionary than storing its inverse separate?
给定一个一对一的字典(双射)àla生
1 2
| for key, value in someGenerator:
myDict[key] = value |
西安反查词典可以很容易的城市综合创新
两个for回路。但这是一个Python的方式吗?我应该写一class Bijection(dict)而不是这本词典manages倒在提供第二加法器和查找功能。或是这样的(或类似的结构(一)已经存在了吗?
- 这个投标怎么样
- @琼斯门茨听起来很完美,谢谢!我接受这个作为答案。使用切片进行反向查找是一个很好的主意
- 从外观上看,bidict只是用正向和反向映射包装了两个单独的python字典,所以它的效率并不比您自己做的更高。实际上,如果您进行了大量的键查找,那么由于函数调用开销,查找速度会慢得多。
- 这几乎不是一个答案,我也没有实际使用它来亲自推荐它的经验。不过,要注意的是,如果我没记错的话,关于该库的API在使用切片表示法时是否是Python式的,还存在着相当激烈的争论。但是,旁观者眼中的美和所有这些。
- @阿雅我看了来源,确实是这样。(见此处),但就我而言,这可能是微不足道的。但在这种情况下,我们可以使用namedbidict。
- @jonclements我可以用这个符号-哈希不应该是有序的,所以除非键或值是显式的整数,否则切片是不可能被误解的…尽管这可能是使用namedbidict的一个原因
- @是的。看来namedbidict会更有效率。
- @但是,如果需要的话,用try: return self._fwd[keyorslice]
except TypeError: return self._bwd[keyorslice.stop]替换bidict的__getitem__可能会加快速度。(该死,我要回复评论中的换行符)
- @确实是托比亚斯基纳。Try/Except块也会减慢速度。在实践中,我发现return d[k] if k in d else something_else比try: return d[k]
except KeyError: return something_else和return d.get(k, something_else)快得多,即两个键查找比允许python生成异常和/或调用实例方法快。就我个人而言,我认为它没有提供足够的附加功能(与使用两个听写相比)来保证它的性能问题,但如果这不是问题,那么它至少具有易于使用的优点。
- @阿雅,我以为try/except对Python来说不是那么可怕吗?无论如何,NamedBidit不能更快,所以如果速度是一个问题,那么必须编写另一个类,它不会使__getitem__过载,但提供了例如getKey(value)之类的内容,或者直接使用dict及其逆项,正如您建议的那样。
- @Tobiaskienzler,我最近不得不优化一个相当复杂的递归函数,它被称为150000次,所以我花了相当长的时间用cProfile分析不同的方法,并通过使用d[k] if k in d方法节省了大量的CPU时间。后来我把它改成使用d = collections.defaultdict(lambda: None); v = d[k]; return something_else if v is None else v,这更好,因为它只需要一个密钥查找,密钥丢失只会发生一次,defaultdict在C中实现。你对namedbidict是正确的,我第一次读错了。
- 假设键/值类型之间没有重叠,另一种选择是:class Bidict(dict): def __setitem__(self, k, v): dict.__setitem__(self, k, v); dict.__setitem__(self, v, k),即对两个方向使用相同的dict,但在您的情况下可能不合适。
- @Aya子类为MutableMapping,而不是dict。stackoverflow.com/questions/3387691/…
- @gotgenes我不知道如何解决与调用__getitem__相关的性能问题。
- @Aya感谢你找到了真正的重复,我只找到了这个,它仅限于你提到的没有键/值冲突的特殊情况。顺便说一下,这个问题应该作为你的建议的翻版而不是我提到的那个问题来打开和关闭。
我过去所做的是创建一个reversedict函数,该函数接受一个dict并返回相反的映射,如果我知道它是一对一的,则返回键的值(如果看到相同的值两次,则抛出异常),否则返回键列表的值。这样,我就不必每次都同时构造两个dict了。特德,反向查找,我可以创建我的听写作为正常的,只是调用通用的reversedict函数结束。
然而,乔恩在评论中提到的Bidict解决方案似乎是更好的解决方案。(我的reversedict函数似乎是他的bidict的~运算符)。
- bidict对于我来说是完美的——它基本上在内部存储了反向字典,但是通过使用slice操作符改进了访问。
如果您想要O(log(n))时间来访问值,您将需要映射的表示和反向映射的表示。
否则,你能做的最好的就是在一个方向上O(log(n)),在另一个方向上O(n))。
编辑:不是O(日志(n)),谢谢Claudiu,但是您仍然需要两个数据结构来实现快速访问时间。这个空间或多或少与dict和reverse dict的空间相同。
- dict没有o(log(n))查找,它们已分摊o(1)查找…
- 是的,应该在我发帖之前查一下。)