我正在尝试反转字典嵌套,使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
但我似乎无法设置所有字典参数(例如contains,getitem,iter)来完成这项工作。你能帮助我吗 ? 如果你有更好的方法来节省CPU和内存并避免此类定义,那就更好了。同样,如果您对改进所描述的架构有建议,请提出。
使用发电机的主要好处之一是降低存储成本。为了访问反向字典,不需要将两个字典加载到内存中。下面我包含了一个 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>