python的可逆字典
Posted
技术标签:
【中文标题】python的可逆字典【英文标题】:Reversible dictionary for python 【发布时间】:2010-11-06 23:48:55 【问题描述】:我想在 Python 中以类似于字典的形式存储一些数据:1:'a', 2:'b'
。每个值都是唯一的,不仅在其他值之间,而且在键之间也是如此。
是否有一个简单的数据结构可以用来获取相应的对象,无论我使用“键”还是“值”询问?例如:
>>> a = 1:'a', 2:'b'
>>> a[1]
'a'
>>> a['b']
2
>>> a[3]
KeyError
“键”是标准的 Python 整数,值是短 (
我当前的解决方案是创建一个反向字典并在我在原始字典中找不到结果时对其进行搜索:
pointsreversed = dict((v, k) for k, v in points.iteritems())
def lookup(key):
return points.get(key) or pointsreversed.key()
这使用了两倍的空间,这不是很好(我的字典可能高达几百兆)并且平均慢 50%。
编辑:正如一些答案中提到的,两个字典不会使内存使用量翻倍,因为它只是字典,而不是其中的项目,即重复。
有没有改进的解决方案?
【问题讨论】:
在你的例子中,你真的是说 a[1] 返回'1'吗?似乎您希望它返回“a”。 (0) pointsreversed.key()??? -- 请复制/粘贴实际工作代码 (1) 平均查找次数应为 N*(2-p) 其中 p = prob(found in 1st dict); “慢 50%”意味着 p 很小或者您引入了开销 (2) 除非您做了一些非凡的事情,否则您的字符串不会被复制,因此您的内存使用量不会翻倍。 (3) 不知道自己是int对象还是str对象是怎么来的? 【参考方案1】:如果您的键和值不重叠,一种明显的方法是将它们简单地存储在同一个字典中。即:
class BidirectionalDict(dict):
def __setitem__(self, key, val):
dict.__setitem__(self, key, val)
dict.__setitem__(self, val, key)
def __delitem__(self, key):
dict.__delitem__(self, self[key])
dict.__delitem__(self, key)
d = BidirectionalDict()
d['foo'] = 4
print d[4] # Prints 'foo'
(您可能还想实现 __init__
、update
和 iter*
方法,以像真正的 dict 一样工作,具体取决于您需要多少功能)。
这应该只涉及一次查找,尽管可能不会为您节省太多内存(毕竟您仍然有两倍数量的 dict 条目)。但是请注意,无论是 this 还是您的原始文件都不会占用两倍的空间:dict 只占用引用的空间(实际上是指针),加上过度分配的开销。您的数据本身占用的空间不会重复两次,因为指向的是相同的对象。
【讨论】:
【参考方案2】:相关帖子:
Python mapping inverse
Python 1:1 mappings
当然,如果所有的值和键都是唯一的,你不能只使用一个字典,并在最初插入 key:value 和 value:key 吗?
【讨论】:
是的,如果所有的键和值都是唯一的,你/可以/使用一个字典。没想到。 +1 他可以,这取决于他还想做什么......例如single_dict.items() 和朋友可能会导致问题和/或过度使用 isinstance()【参考方案3】:在计算机编程的艺术中,Vokume 3 Knuth 有一节介绍了辅助键的查找。就您的问题而言,该值可以被视为辅助键。
第一个建议是做你所做的:按值对键进行有效索引。
第二个建议是设置一个大的btree,它是聚集数据的复合索引,其中分支节点包含值,叶子包含关键数据和指向更大记录的指针(如果有的话)。
如果数据是几何数据(如您的数据所示),则存在称为邮局树的东西。它可以回答诸如离点 x 最近的物体是什么等问题。这里有几个例子:http://simsearch.yury.name/russir/01nncourse-hand.pdf 这种查询的另一个简单选项是四叉树和 k-d 树。 http://en.wikipedia.org/wiki/Quadtree
另一个最终选项是组合散列,您可以将键和值组合成一种特殊的散列,即使您没有这两个值,您也可以对散列进行有效的查找。我在网上找不到很好的组合哈希解释,但它在 TAoCP,第 3 卷第二版第 573 页。
当然,对于其中一些,您可能必须编写自己的代码。但如果内存或性能真的很关键,您可能需要花点时间。
【讨论】:
【参考方案4】:它不应该使用“两倍的空间”。字典只存储对数据的引用,而不是数据本身。因此,如果您有一百万个字符串占用十亿字节,那么每个字典可能会占用额外的 10-2000 万字节——这只是整个存储空间的一小部分。使用两个字典是正确的做法。
【讨论】:
【参考方案5】:将反转的(键,值)对插入到同一个字典中:
a = 1:'a', 2:'b'
a.update(dict((v, k) for k, v in a.iteritems()))
然后您将可以根据需要同时执行这两项操作:
print a[1]
print a['a']
【讨论】:
【参考方案6】:这里是another solution 使用用户定义的类。
还有代码……
# search a dictionary for key or value
# using named functions or a class
# tested with Python25 by Ene Uran 01/19/2008
def find_key(dic, val):
"""return the key of dictionary dic given the value"""
return [k for k, v in symbol_dic.iteritems() if v == val][0]
def find_value(dic, key):
"""return the value of dictionary dic given the key"""
return dic[key]
class Lookup(dict):
"""
a dictionary which can lookup value by key, or keys by value
"""
def __init__(self, items=[]):
"""items can be a list of pair_lists or a dictionary"""
dict.__init__(self, items)
def get_key(self, value):
"""find the key(s) as a list given a value"""
return [item[0] for item in self.items() if item[1] == value]
def get_value(self, key):
"""find the value given a key"""
return self[key]
【讨论】:
但是在这种情况下,您不能直接访问一个值,因为您需要查找它。它降低了字典的兴趣【参考方案7】:我已经这样做了很多年了。与其他解决方案相比,我个人更喜欢它的简单性。
d = 1: 'a', 2: 'b'
dict(zip(d.values(), d.keys()))
【讨论】:
以上是关于python的可逆字典的主要内容,如果未能解决你的问题,请参考以下文章
在 Spyder for Python 中将控制台打印到日志文件是不可逆的