Python中的就地字典反转
我需要颠倒一个列表字典,我不知道如何用英语准确地解释它,所以这里有一些代码可以满足我的需要。它只是占用了太多的内存Python中的就地字典反转,python,list,hashtable,generator,Python,List,Hashtable,Generator,我需要颠倒一个列表字典,我不知道如何用英语准确地解释它,所以这里有一些代码可以满足我的需要。它只是占用了太多的内存 def invert(oldDict): invertedDict = {} for key,valuelist in oldDict.iteritems(): for value in valuelist: try: entry = invertedDict[value]
def invert(oldDict):
invertedDict = {}
for key,valuelist in oldDict.iteritems():
for value in valuelist:
try:
entry = invertedDict[value]
if key not in entry:
entry.append(key)
except KeyError:
invertedDict[value] = [key]
return invertedDict
原始的是列表的dict,结果是列表的dict。这“颠倒”了它
这使得:
{2000: [1, 3], 2001: [1], 440: [2, 3], 441: [2], 1999: [1]}
我需要知道这是否可以实现,因为我当前的策略超过了我使用的字典机器上的物理内存量。您能想出一种使用生成器的方法吗?这并没有在适当的位置执行,而是使用popitem()使用oldDict 我有一种感觉,除非尺寸增加,否则dict的大小永远不会调整,因此您可能需要定期添加并删除一个虚拟项。看
实际上,我看不出有任何方法可以显著提高当前算法的内存使用率。您确实使用迭代器,而不是直接创建新的列表/目录,因此唯一重要的内存使用来自原始字典和新的反向字典 如果你没有足够的内存来使用你实际使用的字典运行这个算法,我所能想到的就是以某种方式避免在内存中同时保留原始dict和反转dict。一种方法是在将项目添加到倒置的dict时从原始dict中删除项目,方法如下:
def invert(old_dict):
inverted = collections.defaultdict(list)
while old_dict:
k,v = old_dict.popitem()
for vi in v:
inverted[vi].append(k)
return inverted
(请注意,我还使用了defaultdict
来简化代码,但是如果您确实需要纯dict
,而不是子类,则可以执行与最初使用try
/类似的操作,除了
)
如果您想在算法完成后保持原始和反向词典都可用,我所能想到的就是将它们存储在磁盘文件中,并找到某种方法一次只加载一个片段。我不知道有哪种标准的Python模块能够将dict存储到磁盘,并且一次只能加载其中的一部分,因此您可能必须为此编写自己的代码。我没有直接的答案。以下是我的一些想法
如果算法是正确的,在现代机器上可能需要数百万个条目才能耗尽RAM。假设这样,您必须使用一些持久性存储,以便数据一次只处理块。为什么不使用具有2列的简单数据库表来存储dict
key value
1 1999
1 2000
1 2001
2 440
2 441
...
然后,您可以使用任一列作为键,方法是在需要的列上选择with
order by
,并使用简单的python代码对其他列的值进行分组。您是否尝试过shelve
?我不知道shelve,谢谢。我想旧的或新的字典都不需要完全加载才能对它们进行操作?shelve只使用字符串键。你可以解决这个问题是的,这正是我想建议的。从旧字典中删除对象,这样你应该保持内存使用量相当恒定(至少在垃圾收集发生时)。这是一种迫使dict调整大小的聪明方法。我现在运行了这个方法,到目前为止它看起来还不错。感谢你注意到“if key not in entry:”是不必要的,这是一个加号。我想我将来会使用shelve,但现在,gnibbler的把戏确实奏效了。
from collections import defaultdict
def invert(oldDict):
invertedDict = defaultdict(list)
i=0
while oldDict:
key, valuelist = oldDict.popitem()
for value in valuelist:
invertedDict[value].append(key)
i+=1
if i%1000==0: # allow the dict to release memory from time to time
oldDict[None]=None
del oldDict[None]
return invertedDict
def invert(old_dict):
inverted = collections.defaultdict(list)
while old_dict:
k,v = old_dict.popitem()
for vi in v:
inverted[vi].append(k)
return inverted
key value
1 1999
1 2000
1 2001
2 440
2 441
...