python中1:1映射的数据结构?

Sal*_*ley 30 python data-structures

我有一个问题,需要一个可逆的1:1键到值的映射.

这意味着有时我想找到一个给定键的值,但有时我想找到给定值的键.键和值都保证唯一.

x = D[y]
y == D.inverse[x]
Run Code Online (Sandbox Code Playgroud)

显而易见的解决方案是每次我想要反向查找时简单地反转字典:反转字典非常容易,这里有一个配方但是对于大字典它可能非常慢.

另一种方法是创建一个新的类,它将两个字典统一起来,每个字典对应一种查找.这很可能很快,但会消耗两倍于单个字典的内存.

那么我可以使用更好的结构吗?

  • 我的应用程序要求这应该非常快,并尽可能少地使用内存.
  • 结构必须是可变的,并且强烈希望变异对象不应该导致它更慢(例如强制完整的重新索引)
  • 我们可以保证键或值(或两者)都是整数
  • 可能需要该结构来存储数千或数百万件物品.
  • Keys&Valus保证是唯一的,即len(set(x))== len(x)代表[D.keys(),D.valuies()]中的x

nos*_*klo 27

另一种方法是创建一个新的类,它将两个字典统一起来,每个字典对应一种查找.这很可能很快,但会消耗两倍于单个字典的内存.

并不是的.你测量过了吗?由于两个字典都会使用与键和值相同的对象的引用,因此所花费的内存将只是字典结构.这不到两倍,并且无论您的数据大小如何都是固定的.

我的意思是不会复制实际数据.所以你要花掉额外的记忆.

例:

a = "some really really big text spending a lot of memory"

number_to_text = {1: a}
text_to_number = {a: 1}
Run Code Online (Sandbox Code Playgroud)

只存在"真正大"字符串的单个副本,因此您最终只需花费更多内存.这通常是负担得起的.

我无法想象一个解决方案,如果你没有花费至少足够的内存来存储反向查找哈希表,那么你在按值查看键时可以获得键查找速度(这正是你在"联合两个"中所做的事情.dicts"解决方案".

  • 我认为这是一个很好的解决方案.但是,你会增加维护字典(内存和计算)的开销,因为现在有两个.我怀疑与其他问题相比,这种开销会很小. (2认同)
  • @Doug&nosklo:我只想强调nosklo的观点.这个问题是时间和空间之间权衡的*经典*例子.如果要确保两端的快速查找,则需要同时维护这两个词典.第二个字典是您为反向查找支付的价格.如果空间开销太大,则需要更慢的解决方案.你可以进行快速反向查找的唯一方法是,为了做到这一点,我们会保留一些*类型的信息...... (2认同)

use*_*918 9

class TwoWay:
    def __init__(self):
       self.d = {}
    def add(self, k, v):
       self.d[k] = v
       self.d[v] = k
    def remove(self, k):
       self.d.pop(self.d.pop(k))
    def get(self, k):
       return self.d[k]
Run Code Online (Sandbox Code Playgroud)

  • 这个类在这个例子中失败:`{1:2,2:4}`必须实现逆方法,恕我直言. (5认同)
  • @PaulPichaureau 这不是 1:1 映射,您正在考虑更通用的 * 可逆 * 字典。在双射 (1:1) 的情况下,如果输入了 `1 -> 2`,那么假设 `2 -> 1` 也必须是。您不能在不违反先决条件的情况下添加然后添加`2 -> 4`。可以在 `add()` 中添加一个简单的检查,例如 `if (k in self.d or v in self.d): # drop or throw` (3认同)
  • 如果域和辅助域不同或具有不同类型,则此方法不起作用。 (2认同)

Sha*_*son 5

另一种方法是创建一个新的类,它将两个字典统一起来,每个字典对应一种查找.这很可能会占用单个字典的两倍内存.

不是真的,因为他们只会持有两个相同数据的引用.在我看来,这不是一个糟糕的解决方案.

您是否考虑过内存数据库查找?我不确定它在速度上的比较,但关系数据库中的查找速度非常快.