【发布时间】:2016-05-06 19:25:20
【问题描述】:
如何将以下嵌套 dict 转换为仅包含具有唯一键集(无论值如何)的列表项的 dict?
我不知道有多少层嵌套,也不关心返回的是哪个列表项,只要它有一组唯一的键(对于该项所属的列表)
(我正在尝试从一个非常长的 YAML 文件中生成一个示例文件以用于文档记录)
input = {
"mylist": [
{
"key1": "1333",
"key2": [
{
"key2a":134,
"key2b":1373
},
{
"key2a":124,
"key2b":136
}
]
},{
"key1": "875",
"key2": [
{
"key2a":999,
"key2b":6567
},
{
"key2a":8765,
"key2b":875
}
]
},{
"key1": "6754",
"key3": 3232
},{
"key1": "34545",
"key3": 34554
}
]
}
需要的输出:
{
"mylist": [
{
"key1": "1333",
"key2": [
{ "key2a":134,
"key2b":1373
}
]
},{
"key1": "6754",
"key3": 3232
}
]
}
我编写了这个(冗长的)代码,通过获取和存储它在列表项对象中找到的所有键来解决它,但我确信这可以用更短的方式完成?
input = collections.OrderedDict(input)
def get_keys(obj,keys=[]):
if isinstance(obj, (dict,collections.OrderedDict)):
for k, v in obj.items():
if not isinstance(v, (dict,collections.OrderedDict)):
keys.append(k)
get_keys(v,keys)
elif isinstance(obj, list):
for elem in obj:
if not isinstance(elem, (dict,collections.OrderedDict,list)):
keys.append(elem)
get_keys(elem,keys)
return keys
def traverse(obj, callback=None):
if isinstance(obj, (dict,collections.OrderedDict)):
value = {k: traverse(v, callback)
for k, v in obj.items()}
elif isinstance(obj, list):
value = [traverse(elem, callback)
for elem in obj]
else:
value = obj
if callback is None:
return value
else:
return callback(value)
def traverse_modify(obj):
def yaml_shortener(obj):
duplicates = []
if isinstance(obj,list) and len(obj)>1:
return_list = []
for i,elem in enumerate(obj):
if not any(Counter(get_keys(elem,keys=[])) == Counter(item) for item in duplicates):
return_list.append(elem)
duplicates.append(get_keys(elem,keys=[]))
return return_list
else:
return obj
return traverse(obj, callback=yaml_shortener)
def shorten_yaml(obj):
return traverse_modify(obj)
print json.dumps(shorten_yaml(input),indent=3)
【问题讨论】:
-
选择条件是什么?例如,为什么
"key2a":999被拒绝而"key2a":134被记录? -
手工编辑的 json :) 值无关紧要。如果一个列表有许多具有相同键结构的项目,则删除除一个之外的所有项目。希望它有意义。
-
所以本质上,它只是随机选择 1 个密钥。换句话说,如果有 4 个 'key2a' 实例,只需保存其中一个,其余的忽略。对吗?
-
我认为关键是必须保持列表中项目的结构完整性,我不能从列表中的单个 dict-items 中删除键。但是可以肯定的是,如果列表中有两个(或更多)项目由 'key2a', [{'key2a':1},{'key2a:2}] 组成,那么除了一个之外的所有项目都可以删除
-
为什么是
"key1": "875"?不见了?