python的可逆字典

时间:2009-06-30 12:15:08

标签: python dictionary hashtable

我想以类似的形式将一些数据存储在Python中:{1:'a', 2:'b'}。每个值都是唯一的,不仅仅是其他值,还包括键。

是否有一个简单的数据结构,我可以使用它来获取相应的对象,无论我是否要求使用'key'或'value'?例如:

>>> a = {1:'a', 2:'b'}
>>> a[1]
'a'
>>> a['b']
2
>>> a[3]
KeyError

'keys'是标准的python int,值是短(<256char)字符串。

我目前的解决方案是创建一个反向字典并在原始字典中找不到结果时进行搜索:

pointsreversed = dict((v, k) for k, v in points.iteritems())
def lookup(key):
    return points.get(key) or pointsreversed.key()

这使用了两倍的空间,这不是很好(我的词典可以达到几百兆)并且平均减慢50%。

编辑:正如在几个答案中所提到的,两个dicts不会使内存使用量增加一倍,因为它只是字典,而不是内部的项目,即重复。

有没有改进的解决方案?

7 个答案:

答案 0 :(得分:11)

如果你的键和值不重叠,一个明显的方法是简单地将它们存储在同一个dict中。即:

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__updateiter*方法的操作,以便像真正的字典一样运行,具体取决于您需要多少功能。)< / p>

这应该只涉及一次查找,但可能不会在内存中节省很多(毕竟你仍然有两倍的dict条目)。但请注意,这个和你的原始版本都不会占用两倍的空间:dict只占用引用空间(有效指针),加上过度分配开销。由于指向相同的对象,因此数据本身占用的空间不会重复两次。

答案 1 :(得分:8)

相关帖子:

Python mapping inverse

Python 1:1 mappings

当然,如果所有的值和键都是唯一的,那么你不能只使用一个字典,并且最初插入key:value和value:key?

答案 2 :(得分: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页。

当然,对于其中一些,您可能必须编写自己的代码。但如果内存或性能真的很关键,那么你可能需要花时间。

答案 3 :(得分:1)

不应该使用“两倍的空间”。字典只存储对数据的引用,而不是数据本身。因此,如果你有一百万个字符串占用十亿字节,那么每个字典可能需要额外的1000万到2000万字节 - 这只是整个存储的一小部分。使用两个词典是正确的。

答案 4 :(得分:0)

将相反的一对(键,值)插入到同一个字典中:

a = {1:'a', 2:'b'}
a.update(dict((v, k) for k, v in a.iteritems()))

然后,您可以根据需要同时执行这两项操作:

print a[1]
print a['a']

答案 5 :(得分:0)

这是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]

答案 6 :(得分:0)

我已经用这种方式做了很多年了。我个人比其他解决方案更喜欢它的简单性。

d = {1: 'a', 2: 'b'}
dict(zip(d.values(), d.keys()))
相关问题