Python - 反向嵌套字典 dict 中的 dict

问题描述 投票:0回答:1

我正在尝试反转字典嵌套,使dict1中的dict2变成dict2中的dict1。为此,我遵循了链接中的方法: Pythonic 方式反转嵌套字典

这个字典嵌套来自一个函数,例如:

#All functions and property for my_object0
class my_class0(object):
    def __init__(self, input, **kwargs):
        self.my_listA = ()
        ...

    def my_function0(self, **kwargs):
        for key, value in my_class(kwargs).my_function(kwargs):
            self.my_listA = ( (key2, value2) for key2, value2 in value.items() )
            ...
            if hasattr(self, key):
                yield from getattr(self, key)

    @properties
    def my_property(self):
        for key, value in self.my_listA:
            yield key, value


#All functions and property for queries of object0 information (what?)
class my_class(object):
    def __init__(self, **kwargs):
        ...
        self.my_listB = []

    def my_function(self, **kwargs):
        my_list3 = []
        for key, value in my_class3(kwargs).my_function3(kwargs3):
            ...
            my_list3.append(value)
        self.my_listB = my_list3
        yield from self.my_functionZ(kwargsZ) #my problem is here !!!! i need to return dict2 in dict1 and not dict1 in dict2    

    def my_functionZ(self, **kwargs):
        for key, value in my_class2(kwargs).my_function2(kwargs2):
            ...
            yield key, value


#All functions and property for data of queries (where?)
class my_class2(object):
    def __init__(self, **kwargs):
        ...
    def my_function2(self, my_list2, **kwargs):
        for item2 in my_list2: #my_list2 = dir(self)
            ...
            yield item2, getattr(self, item2)(self)

    def item2(self, self2, **kwargs):
        if call1:
            return "my_data1"
        elif call2:
            return "my_data2"
        ...
...

if __name__ == '__main__':
    ...
    for item in my_list:
        print( dict( my_class0(item).my_function0() ) )

我创建了一个解决问题的函数:

def flip_dict_in_dict1(generator1):
    dict3 = {}
    for key, val in generator1:
        for key2, val2 in val.items():
            dict3.setdefault(key2, {}).update({key:val2})
    return dict3

例如:字典

d0 = {
'Bob' : {'item1':3, 'item2':8, 'item3':6},
'Jim' : {'item1':6, 'item4':7},
'Amy' : {'item1':999,'item2':5,'item3':9,'item4':2}
}

对应生成器

d0 = (
('Bob', {'item1':3, 'item2':8, 'item3':6}),
('Jim', {'item1':6, 'item4':7}),
('Amy', {'item1':999,'item2':5,'item3':9,'item4':2})
)

经过测试

print( flip_dict_in_dict( d0 ) )

控制台显示

{'item1': {'Bob': 3, 'Jim': 6, 'Amy': 999}, 'item2': {'Bob': 8, 'Amy': 5}, 'item3': {'Bob': 6, 'Amy': 9}, 'item4': {'Jim': 7, 'Amy': 2}}

此功能正确,使得

yield from flip_dict_in_dict1( self.my_functionZ(kwargsZ) ).items()

问题在于嵌套字典的大小。这些字典可以包含 1 KB 到 10 GB 的数据。 我无法将整个 dict3 字典存储在内存中。所以我创建了一个字典类。

class flip_dict_in_dict2(dict):
    def __init__(self, mirror):
        self.mirror = mirror
        self.dict2 = self.mirroir_dict2
    def __contains__(self, key3) -> bool:
        return self.dict2(self, key3)
    def __getitem__(self, key):
        return self.dict2(self, key)
    def __iter__(self) -> Iterator:
        return iter( self.dict2(self) )
    class mirroir_dict2(dict):
        def __init__(self, parent, key1):
            self.parent = parent
            self.key1 = key1
        def __contains__(self, key2) -> bool:
            print( self.key1, key2 )
            return key2 in self.parent.mirror
        def __getitem__(self, key2):
            return self.parent.mirror[key2][self.key1]
        def __iter__(self) -> Iterator:
            print("****")
            for value in self.parent.mirror.values():
                yield value

但我似乎无法设置所有字典参数(例如containsgetitemiter)来完成这项工作。你能帮助我吗 ? 如果你有更好的方法来节省CPU和内存并避免此类定义,那就更好了。同样,如果您对改进所描述的架构有建议,请提出。

python dictionary nested reverse yield
1个回答
0
投票

使用发电机的主要好处之一是降低存储成本。为了访问反向字典,不需要将两个字典加载到内存中。下面我包含了一个 ReverseDict 类,它实现了只读访问所需的方法。如果您希望稍后能够更新它以便可以编写字典,则必须对其进行修改以包含诸如 update、setdefault 和其他方法之类的写入方法。

class ReverseDict(UserDict):
    def __init__(self, d: dict) -> None:
        self.data = d
        
    def __getitem__(self, key):
        result = {}
        for k, v in self.data.items():
            if key in v:
                result[k] = v[key]
        return result
    
    def __iter__(self):
       return iter(self.keys())
    
    def keys(self):
        k = list(self.data.keys())[0]
        return self.data[k].keys()
    
    def items(self):
        return ((k, self[k]) for k in self.keys())

    def values(self):
        return (self[k] for k in self.keys())

您可以按如下方式实现此类:

 rd = ReverseDict(d)
    for k,v in rd.items():
        print(k, v)
    for k in rd:
        print(k)
    print(rd.keys())
    print(rd.values())
    print(rd.items())

Output:
item1 {'Bob': 3, 'Jim': 6, 'Amy': 999}
item2 {'Bob': 8, 'Amy': 5}
item3 {'Bob': 6, 'Amy': 9}
item1
item2
item3
dict_keys(['item1', 'item2', 'item3'])
<generator object ReverseDict.values.<locals>.<genexpr> at 0x10821b3e0>
<generator object ReverseDict.items.<locals>.<genexpr> at 0x10821b3e0>
© www.soinside.com 2019 - 2024. All rights reserved.