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
    ...