附加到Python中预先存在的键的值

附加到Python中预先存在的键的值,python,python-3.x,Python,Python 3.x,如果列表中有n个不同值和键长度的嵌套字典: original_list = [ {'animal': {'mammal': {'herbivore': 'zebra'}}}, {'animal': {'mammal': {'herbivore': 'deer'}}}, {'animal': {'mammal': {'carnivore': 'tiger'}}}, {'animal': {'mammal': {'herbivore': 'lion'}}},

如果列表中有n个不同值和键长度的嵌套字典:

original_list = 
[
    {'animal': {'mammal': {'herbivore': 'zebra'}}},
    {'animal': {'mammal': {'herbivore': 'deer'}}},
    {'animal': {'mammal': {'carnivore': 'tiger'}}},
    {'animal': {'mammal': {'herbivore': 'lion'}}},
    {'furniture': {'chair'}}
]
如何使用相同的嵌套键聚合值以获得以下结果:

[
    {'animal': {'mammal': {'herbivore': 'zebra', 'deer'}}},
    {'animal': {'mammal': {'carnivore': 'tiger', 'lion'}}},
    {'furniture': 'chair'}
]
或更精简的视图,如

[
    {'animal':
        {'mammal':
            {'herbivore': ['zebra', 'deer']},
            {'carnivore': ['tiger', 'lion']}
        }
    },
    {'furniture': ['chair']}
]

我试过这个:

from collections import defaultdict
d = defaultdict(list)
for item in original_list:
    for k, v in item.items():
        d[k].append(v)
但这只是聚集在列表的根(而不是内部级别),如:


由于来自输入的嵌套dict的深度可变,因此无法使用固定的嵌套
for
循环来处理它。相反,首先在列表中记录每个记录的键的路径,并使用映射dict将路径映射到当前值应附加到的列表(将路径从列表转换为元组以进行散列)。如果映射dict中还不存在该路径,则构建一个新记录作为dict,并使用
for
循环,通过使用临时节点dict指向当前子dict级别,将除最后一个键路径之外的每个级别初始化为dict。首先从路径中弹出最后一个键,以便将最后一个级别初始化为列表。将当前值附加到列表中,无论是来自映射dict还是新生成的记录:

output = []
mapping = {}
for record in original_list:
    path = []
    while True:
        key, value = next(iter(record.items()))
        path.append(key)
        if not isinstance(value, dict):
            break
        record = value
    signature = tuple(path)
    if signature not in mapping:
        node = {}
        output.append(node)
        last_key = path.pop()
        for key in path:
            node[key] = node = {}
        node[last_key] = mapping[signature] = []
    mapping[signature].append(value)
使用示例输入(将老虎更正为食肉动物,将家具更正为字符串而不是一组字符串),
输出变为:

[{'animal': {'mammal': {'herbivore': ['zebra', 'deer']}}},
 {'animal': {'mammal': {'carnivore': ['tiger', 'lion']}}},
 {'furniture': ['chair']}]

演示:

您正在使用的数据结构(只有一个键的dict!?)没有多大意义,您应该考虑使用正确嵌套的dict,或者使用具有元组键的单个dict,甚至使用树结构。但对于您的要求,您可以使用以下内容:

从集合导入defaultdict
d=默认DICT(列表)
对于原始列表中的条目:
打印('条目',条目)
键=[]
val=list(entry.values())[0]
而类型(条目)=记录:
key.append(列表(entry.keys())[0])
entry=list(entry.values())[0]
d[元组(键)]。追加(条目)
out=[]
对于d中的k:
条目={k[-1]:d[k]}
对于k[-2::-1]中的k0:
entry={k0:entry}
out.append(条目)
打印(输出)

您试过这个吗?输入的最后一项应该是
{'furniture':'chair'}
,而不是
{'furniture':{'chair'}
,对吗?还是你真的想和一组人打交道?这个项目的输出应该是
{'furniture':['chair]}
,而不是
{'furniture':{'chair'}
。它应该是{'furniture':['chair']}。还更新了帖子(可能)以获得更好的(可读性更强的)输出:
[{'animal':{'哺乳动物:{'herbivore':['斑马鹿']},{'carnivore':['tiger',['lion']},{'furniture':['chair']}
谢谢你解释这个解决方案。但是,这个过程是否可以扩展到更高层次的聚类,以消除重复?例如,
[{'animal':{'meanimal':{'herbivore':['zebra','deer']},{'carnivore':['tiger','lion']},{'furniture':['chair']}]
中的解决方案解决了将isi应用于
输出时的问题,但可能有更好的解决方案。
output = []
mapping = {}
for record in original_list:
    path = []
    while True:
        key, value = next(iter(record.items()))
        path.append(key)
        if not isinstance(value, dict):
            break
        record = value
    signature = tuple(path)
    if signature not in mapping:
        node = {}
        output.append(node)
        last_key = path.pop()
        for key in path:
            node[key] = node = {}
        node[last_key] = mapping[signature] = []
    mapping[signature].append(value)
[{'animal': {'mammal': {'herbivore': ['zebra', 'deer']}}},
 {'animal': {'mammal': {'carnivore': ['tiger', 'lion']}}},
 {'furniture': ['chair']}]