带两个键的Python字典
我想用书架储存一本大词典。更具体地说,我拥有的是一本字典字典,就像一个矩阵:带两个键的Python字典,python,shelve,Python,Shelve,我想用书架储存一本大词典。更具体地说,我拥有的是一本字典字典,就像一个矩阵: dict[key1][key2] = value 键的数量大约为5.000,这使得由5.000x5.000个元素组成的矩阵无法存储在我的4Gb内存中。出于这个原因,我认为搁置可能是一个很好的解决办法 尽管如此,我还没有找到任何关于如何高效地构建词典词典的文档 到目前为止,我所做的是使用shelve创建一个包含常规词典的词典: def create_entry(key1,key2,value,shelf): # she
dict[key1][key2] = value
键的数量大约为5.000,这使得由5.000x5.000个元素组成的矩阵无法存储在我的4Gb内存中。出于这个原因,我认为搁置可能是一个很好的解决办法
尽管如此,我还没有找到任何关于如何高效地构建词典词典的文档
到目前为止,我所做的是使用shelve创建一个包含常规词典的词典:
def create_entry(key1,key2,value,shelf): # shelf is the opened shelve file
if key1 not in shelf: # first time we see this key, initialise it
shelf[key1]={}
# add the contents
shelf[key1][key2]=value
这是可行的,但似乎应该有更好的方法来充分利用搁置。有什么想法吗?您的解决方案唯一真正的问题是,工具架通过酸洗来存储值,因此,您的每个第二级DICT必须在每次分页到磁盘时进行酸洗和取消酸洗,这可能会带来巨大的性能成本。(当然,每一个第二级口述都必须放在内存中,但这可能不是问题。) 如果这不重要,你现在做的很好。但如果是这样,还有两个选择 您可以使用比shelve更复杂的数据库,并围绕它构建自己的包装器 或者,简单得多:只需使用一个单级dict,并将对作为键:
def create_entry(key1, key2, value, shelf):
shelf[(key1, key2)] = value
这样做的缺点是,如果需要迭代key1
子字典中的所有键或值,则必须迭代整个工具架。它并不复杂((key2代表key1,key2在shelf中,如果key1==key)
),但速度会慢得多
上面的代码实际上不能直接用于
搁置
,因为键必须是字符串。但是有非常简单的方法来结束它;正如shelve
pickle和unpickle值一样,您可以编写一个包装器,然后对键进行字符串化和解析,例如:
def _mapkey(self, key):
return ','.join(map(str, key))
def _unmapkey(self, key):
return tuple(map(int, key.split(',')))
def __getitem__(self, key):
return self.shelf[self._mapkey(key)]
def __iter__(self):
return map(self._unmapkey, self.shelf)
# etc.
为了提高效率,最好使用fork或子类shelve
,这样您就可以为底层dbm
键生成bytes
,而不是生成str
,以便shelve
可以对其进行编码。然后你可以这样做:
def _mapkey(self, key):
return struct.pack('>II', key)
def _unmapkey(self, key):
return struct.unpack('<II', key)
def\u映射键(self,key):
返回结构包('>II',键)
def_解锁(自身,钥匙):
return struct.unpack(“您的解决方案唯一真正的问题是,工具架通过酸洗来存储值,因此每次将第二级dict分页到磁盘时,都必须对其进行酸洗和取消酸洗,这可能会带来巨大的性能成本。(当然,每一个第二级口述都必须放在内存中,但这可能不是问题。)
如果这不重要,你所做的是好的。但如果是,还有两个选择
您可以使用比shelve更复杂的数据库,并围绕它构建自己的包装器
或者,简单得多:只需使用一个单级dict,并将对作为键:
def create_entry(key1, key2, value, shelf):
shelf[(key1, key2)] = value
这样做的缺点是,如果需要迭代key1
子字典中的所有键或值,则必须迭代整个工具架。这并不复杂((key2表示key1,key2表示shelf中的key1==key)
),但速度会慢得多
上面的代码实际上并不直接适用于shelve
,因为键必须是字符串。但是有非常简单的方法来包装它;就像shelve
pickle和unpickle值一样,您可以编写一个包装器,然后对键进行字符串化和解析,例如:
def _mapkey(self, key):
return ','.join(map(str, key))
def _unmapkey(self, key):
return tuple(map(int, key.split(',')))
def __getitem__(self, key):
return self.shelf[self._mapkey(key)]
def __iter__(self):
return map(self._unmapkey, self.shelf)
# etc.
为了提高效率,最好使用fork或子类shelve
,这样您就可以为底层dbm
键生成bytes
,而不是生成str
,以便shelve
可以对其进行编码。然后您可以执行以下操作:
def _mapkey(self, key):
return struct.pack('>II', key)
def _unmapkey(self, key):
return struct.unpack('<II', key)
def\u映射键(self,key):
返回结构包('>II',键)
def_解锁(自身,钥匙):
返回struct.unpack(‘数据库怎么样?数据库怎么样?非常感谢。到目前为止,我的实现没有内存问题,我确实需要迭代两个键,所以我会保持原样。将来我会考虑创建数据库的选项…@Muntsa:作为键的对键实现在迭代中没有问题事实上,它变得更简单(而且可能更有效)-而不是对于key1-In-shelf:key2-In-shelf[key1]:
,您可以只对键1执行,键2在工具架中执行:
。问题是当您需要只迭代key1
,或迭代特定的key1
。@abarnert看起来您到处都在“工具架”上这与我的用例类似,dict[str”(100.0200.0)][str(an_integer)]=some_floating_value。在将其存储到shelve后,我需要访问这些键,并按some_floating_value和str(an_integer)对它们进行排序(见上文),这就是我真正需要“备用键”的原因as int.shelve是一个很好的用例吗?也碰到了这个-这个适合我的用例吗?@abarnert我的用例大约有10^4个外键(主键,如上面的键1)和10^4个内键(次键,如上面的键2).仔细查看后,我注意到我不需要存储所有的键,但这意味着在为一个键1编写整个工具架(键1,键2)后,将有更多的重载和弹出键(我只需要存储键2的前100个键,使用一些距离度量),所以我可以在计算完某个特定键1的所有键2之后删除它们。此外,我不知道如何在搁置中弹出键。@ekta:如果您有10^8个键,并且需要对它们进行排序或将它们视为两个值并仅基于其中一个值选择所有内容,那么您肯定需要一个功能更强大的数据库而shelve
。由于sqlite3
包含在stdlib中,不需要设置,是的,这是一个不错的选择。但这确实意味着您必须在