Python 双射映射的大规模优化实现

Python 双射映射的大规模优化实现,python,data-structures,Python,Data Structures,这里有一个有趣的问题:给定大量的文本数据(约5 GB的单词作为字符串),我需要构建一个映射,使每个单词都与一个唯一的整数相关联。需要注意的是,它需要以另一种方式工作——每个整数也应该与一个唯一的单词相关联,因此它是一个双射映射 我还需要能够快速查找一个单词的关联号码 以下是我能想到的最幼稚的实现: data_structure = [] for word in giant_list_of_words: if (word not in data_structure):

这里有一个有趣的问题:给定大量的文本数据(约5 GB的单词作为字符串),我需要构建一个映射,使每个单词都与一个唯一的整数相关联。需要注意的是,它需要以另一种方式工作——每个整数也应该与一个唯一的单词相关联,因此它是一个双射映射

我还需要能够快速查找一个单词的关联号码

以下是我能想到的最幼稚的实现:

   data_structure = []
   for word in giant_list_of_words:
      if (word not in data_structure):
         data_structure.append(word)
   return data_structure

   def lookup(data_structure, i):
       return data_structure[i]
使用这种方法,只需将单词映射到列表中的索引即可。构建映射很慢,但查找很快

以下是另一种方法:

def mapping():
   data_structure = {}
   count = 0
   for word in giant_list_of_words:
      if (word not in data_structure):
         data_structure[word] = count
         count += 1
   return data_structure

def lookup(data_structure, i):
   retval = ''
   for key in data_structure:
      if (data_structure[key] == i):
          retval = key
          break
   return retval

它构建得很快,但索引速度很慢。有什么想法吗?

我认为很少有绝对最优的方法来解决Python中的数据结构设计问题,但对于这个问题,有一个很好的候选者

Python中的每个不同对象(包括字符串)都有一个唯一的idobj号,并且在对象的生命周期内不会更改

碰巧_ctypes模块有一个名为PyObj_FromPtr的函数,该函数通过其id查找对象:

>>>word='supercalifragilisticexpialadocous' >>>word\u id=idword >>>字号 139817888649440 >>>从类型导入PyObj\u从ptr >>>PyObj_fromtrword_id “超级飞行体验” 这一切都内置于语言中——Python将这些id分配给您的对象,无论您是否需要它们,而且查找速度很快,因为作为CPython实现细节,对象的id是其内存地址。因此,很难想象有任何更有效的解决方案来解决这个问题。

选项1 如果字符串具有以下属性:

字符串不区分大小写。苹果 仅使用字符0-9和a-z 否“/\:;,.!@$%^&*{}[]+- 然后,可以使用36进制表示法将字符串转换为整数

hash_val = int("apple", base=36)
选择2 请注意,python字符串具有内置的哈希函数:

words = [
    "apple",
    "banana",
    "apple"
    "apple",
    "kiwi",
    "honeydew",
    "kiwi",
]
d = dict()
d_inv = dict()
for word in words:
    hval = hash(word)
    d[word] = hash(word)
    d_inv[hval] = word

print(
    "\n".join(
        str(key).ljust(20) + str(val) for key, val in d.items()
    )
)

但是,哈希值仅在程序运行时保持不变。每次关闭程序时,它都会发生变化。您必须将它们保存到文件或其他文件中。一次运行时,hashapple是1406220762,下一次运行时是1187353108

如果您需要双向查找,您可以构建两个字典吗?或者更确切地说,由于与单词关联的数字是序列0,1,2,3中的整数,。。。另一个查找可以是列表,而不是字典。这会占用太多内存吗?可能,因为它基本上是在内存中加载的整个数据集的两个副本,所以不会是每个字符串的两个副本-每个字符串只有两个指针。选项2不起作用,因为两个不同的字符串可以具有相同的哈希。