我有两个字典,它们具有相似的结构......意味着它们(应该)具有相同的键结构,即使在嵌套键中也是如此.此外,这些dicts几乎可以有任何类型的嵌套结构... list,dict等...我希望能够遍历这些字典,并获取这两个值并从函数返回它们.
简单示例:
dict_a = {'a':1, 'b':2, 'c':{'d':3}}
dict_b = {'a':2, 'b':4, 'c':{'d':6}}
#Note the structure is the same for these dicts
#I want to be able to do something like:
>>get_values( dict_a, dict_b)
[(1,2),(2,4),(3,6)]
Run Code Online (Sandbox Code Playgroud)
我通过遍历一个字典,然后将每个键(或索引,如果它遇到列表)附加到列表中......作为一种键路径来提出解决方案:
key_map = []#A list of all key-paths for a dictionary
generate_key_paths(dict_a, [], key_map)
def generate_key_paths(value, key_list,key_map ):
new_list = [item for item in key_list]
if isinstance( value, dict):
#Handle list
for key, val in value.iteritems():
new_list.append( key)
self._generate_key_paths( val, new_list, key_map )
new_list = [item for item in key_list]
elif isinstance( value, list ):
#Handle list
for idx,item in enumerate(value):
new_list.append( idx )
self._generate_key_paths( item, new_list, key_map )
new_list = [item for item in key_list]
else:
#Handle data--reached farthest point you can go
#So just append (key-path, value) to key_map
key_map.append((new_list, value ) )
Run Code Online (Sandbox Code Playgroud)
然后,一旦你有一个关键路径,值元组的列表...采取路径,并尝试在第二个字典上达到它以获得其价值...
val_list = []
for item in key_map:
value = get_value( item[0] )
if value is not None:
val_list.append( (item[1], value ) )
def get_value( key_list ):
value = dict_b
for item in key_list:
try:
value = value[item]
except:
value = None
break
return value
Run Code Online (Sandbox Code Playgroud)
这对于字典可能具有的所有结构都很有效,但它似乎很多工作.有更多的pythonic方式实现这一目标吗?有更快,更有效的方式吗?
编辑:我正在寻找一个不是列表或字典的值,所以当达到这些值时,它应该在它们内部迭代,直到找到一个值.保证如果它是一个列表,它将是一个dicts列表,所以应该总是存在某种键:值关系.
例如,可能的dict可能如下所示:
dict_a = {'a':1, 'b':2, 'c':[{'d':5},{'e':6}]}
dict_b = {'a':2, 'b':4, 'c':[{'d':10},{'e':12}]}
回答: [(1,2), (2,4), (5,10), (6,12)]
nin*_*cko 10
你正在寻找一个等价的flatten(zipTree(...))(函数不存在,但其名称应该得到我的观点).
from collections import Mapping
def treezipFlat(t1,t2):
if isinstance(t1,Mapping) and isinstance(t2,Mapping):
assert set(t1)==set(t2)
for k,v1 in t1.items():
v2 = t2[k]
for tuple in treezipFlat(v1,v2):
yield tuple
else:
yield (t1,t2)
Run Code Online (Sandbox Code Playgroud)
演示:
>>> dict_a = {'a':1, 'b':2, 'c':{'d':3}}
>>> dict_b = {'a':2, 'b':4, 'c':{'d':6}}
>>> list( treezipFlat(dict_a, dict_b) )
[(1, 2), (3, 6), (2, 4)]
Run Code Online (Sandbox Code Playgroud)
您还可以通过增加函数来产生路径元组,如下所示:
from collections import Mapping
def treezipItems(t1,t2, path=[]):
if isinstance(t1,Mapping) and isinstance(t2,Mapping):
assert set(t1)==set(t2)
for k,v1 in t1.items():
v2 = t2[k]
for tuple in treezipItems(v1,v2, path=path+[k]):
yield tuple
else:
yield (path, (t1,t2))
>>> list( treezipItems(dict_a, dict_b) )
[(['a'], (1, 2)), (['c', 'd'], (3, 6)), (['b'], (2, 4))]
Run Code Online (Sandbox Code Playgroud)
Imho我觉得这里的自然是一个叫做的函数treezip:
def treezip(t1,t2):
if isinstance(t1,Mapping) and isinstance(t2,Mapping):
assert set(t1)==set(t2)
R = {}
for k,v1 in t1.items():
v2 = t2[k]
R[k] = treezip(v1,v2)
return R
else:
return (t1,t2)
>>> from pprint import pprint as pp
>>> treezip(dict_a, dict_b)
{'a': (1, 2), 'c': {'d': (3, 6)}, 'b': (2, 4)}
Run Code Online (Sandbox Code Playgroud)
然后调用一个函数flattenValues(或者flattenItems如果你想保存键).