将具有列表值的 Python 字典列表转换为具有单个值的字典的平面列表
Convert a Python list of dictionaries with list value to a flat list of dictionary with single value
问题陈述
给定字典列表:
p = [
{'x': 1,
'a': [12, 14, 16],
'b': [13, 15],
'y': 8},
{'x': 2,
'a': [22, 24],
'b': [23, 25, 27],
'y': 9}
]
一些键('a'
和 'b'
)以列表的形式存在,而其他键('x'
和 'y'
)作为单个值--
我想创建一个相当扁平的字典,其中 list 键值被分隔成单独的键 'a_1'
、'a_2'
、...、'b_1'
、'b_2'
、...等,同时保持 单个 键值不变。
t = [
{'x': 1,
'a_1': 12,
'a_2': 14,
'a_3': 16,
'b_1': 13,
'b_2': 15,
'y': 8},
{'x': 2,
'a_1': 22,
'a_2': 24,
'b_1': 23,
'b_2': 25,
'b_3': 27,
'y': 9}
]
部分解决方案
我可以使用以下代码将一个具有列表值的键 'a'
转换为具有单个值的字典:
q = [{'a_'+str(i+1): obj['a'][i]
for i in range(len(obj['a']))}
for obj in p]
print (q)
输出如下:
[
{'a_1': 12,
'a_2': 14,
'a_3': 16},
{'a_1': 22,
'a_2': 24}
]
但不知道如何对多个键执行此操作...特别是对那些值为 list
类型的键执行此操作,否则只需保留键值...最后合并所有键值到外循环中的一个字典 for obj in p
.
使用嵌套迭代,isinstance
检查类型,enumerate
获取项目索引
例如:
result = []
for i in p:
temp = {}
for k, v in i.items():
if isinstance(v, list):
for idx,j in enumerate(v, 1):
temp[f"{k}_{idx}"] = j
else:
temp[k] = v
result.append(temp)
print(result)
输出:
[{'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'x': 1, 'y': 8},
{'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'x': 2, 'y': 9}]
您可以进行如下操作:
def parse_dict(d):
new_dict = {}
for key,val in d.items():
if isinstance(val,list):
new_dict.update({f'{key}_{i+1}':v for i,v in enumerate(val)})
else:
new_dict[key] = val
return new_dict
result = [parse_dict(d) for d in p]
结果输出:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8},
{'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]
主要想法是通过创建一个新函数来分离职责,然后从元素角度考虑...
希望这对解决问题有更多帮助。
更新:
如果你坚持不做一个函数,找一个(又长又难读)一个衬里:
[ {**{key:val for key,val in d.items() if not isinstance(val,list)},**{f'{key}_{i}' if isinstance(val,list)else key : v if isinstance(val,list)else val for key,val in d.items() if isinstance(val,list) for i,v in enumerate(val)}} for d in p]
输出:
[{'x': 1, 'y': 8, 'a_0': 12, 'a_1': 14, 'a_2': 16, 'b_0': 13, 'b_1': 15},
{'x': 2, 'y': 9, 'a_0': 22, 'a_1': 24, 'b_0': 23, 'b_1': 25, 'b_2': 27}]
(注意顺序变了)
你的要求有点棘手,但我会尽力的。
让我们继续,
所以我的方法是使用函数(定义)
def get_new(l):
N = l.copy()
for a in range(len(N)):
for b in N[a].keys():
if b in ['a','b']:
i = 1
while N[a][b]: # while N[a][b] is not empty.
key = str(b) + '_' + str(i)
i += 1
N[a][key] = N[a][b].pop(0)
del N[a][b]
return N
以上函数获取您的初始列表和return您要求的列表
字典中的函数循环及其内部键,对于每个 'a' 和 'b' 键,它将更改每个列表值的键
键像 str(a)+'_'+i
i 是完美的索引 +1
values as N[a][b][i] # 因为它每次都弹出索引 0。
删除 N[a][b] 准备好其特定键值。
我是能够想出(又是部分)列表理解式解决方案:
t = []
for obj in p:
t.append(dict([]))
[t[-1].update({key+'_'+str(i+1): val[i]
for i in range(len(obj[key]))})
if isinstance(obj[key], list) else
t[-1].update({key: val})
for key, val in zip(obj.keys(), obj.values())
]
p
中项目 (obj
) 的一个显式循环,其中在循环内创建一个新字典,并根据项目值是否向其中添加术语是不是列表...感谢我之前的回答者指出 isinstance(obj, type)
函数。
所以,打印 t
得到:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8},
{'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]
一个不值得骄傲的 这个解决方案的优点是:它不使用 f'{key}_{i+1}'
功能(虽然两个优雅的求解器都使用过,对我来说似乎有点晦涩——原谅我的无知)!
您可以使用列表理解:
p = [{'x': 1, 'a': [12, 14, 16], 'b': [13, 15], 'y': 8}, {'x': 2, 'a': [22, 24], 'b': [23, 25, 27], 'y': 9}]
r = [{a if not isinstance(b, list) else f'{a}_{l}':b if not isinstance(b, list) else j
for a, b in i.items() for l, j in enumerate((b if isinstance(b, list) else [b]), 1)}
for i in p]
输出:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8}, {'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]
问题陈述
给定字典列表:
p = [
{'x': 1,
'a': [12, 14, 16],
'b': [13, 15],
'y': 8},
{'x': 2,
'a': [22, 24],
'b': [23, 25, 27],
'y': 9}
]
一些键('a'
和 'b'
)以列表的形式存在,而其他键('x'
和 'y'
)作为单个值--
我想创建一个相当扁平的字典,其中 list 键值被分隔成单独的键 'a_1'
、'a_2'
、...、'b_1'
、'b_2'
、...等,同时保持 单个 键值不变。
t = [
{'x': 1,
'a_1': 12,
'a_2': 14,
'a_3': 16,
'b_1': 13,
'b_2': 15,
'y': 8},
{'x': 2,
'a_1': 22,
'a_2': 24,
'b_1': 23,
'b_2': 25,
'b_3': 27,
'y': 9}
]
部分解决方案
我可以使用以下代码将一个具有列表值的键 'a'
转换为具有单个值的字典:
q = [{'a_'+str(i+1): obj['a'][i]
for i in range(len(obj['a']))}
for obj in p]
print (q)
输出如下:
[
{'a_1': 12,
'a_2': 14,
'a_3': 16},
{'a_1': 22,
'a_2': 24}
]
但不知道如何对多个键执行此操作...特别是对那些值为 list
类型的键执行此操作,否则只需保留键值...最后合并所有键值到外循环中的一个字典 for obj in p
.
使用嵌套迭代,isinstance
检查类型,enumerate
获取项目索引
例如:
result = []
for i in p:
temp = {}
for k, v in i.items():
if isinstance(v, list):
for idx,j in enumerate(v, 1):
temp[f"{k}_{idx}"] = j
else:
temp[k] = v
result.append(temp)
print(result)
输出:
[{'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'x': 1, 'y': 8},
{'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'x': 2, 'y': 9}]
您可以进行如下操作:
def parse_dict(d):
new_dict = {}
for key,val in d.items():
if isinstance(val,list):
new_dict.update({f'{key}_{i+1}':v for i,v in enumerate(val)})
else:
new_dict[key] = val
return new_dict
result = [parse_dict(d) for d in p]
结果输出:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8},
{'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]
主要想法是通过创建一个新函数来分离职责,然后从元素角度考虑...
希望这对解决问题有更多帮助。
更新:
如果你坚持不做一个函数,找一个(又长又难读)一个衬里:
[ {**{key:val for key,val in d.items() if not isinstance(val,list)},**{f'{key}_{i}' if isinstance(val,list)else key : v if isinstance(val,list)else val for key,val in d.items() if isinstance(val,list) for i,v in enumerate(val)}} for d in p]
输出:
[{'x': 1, 'y': 8, 'a_0': 12, 'a_1': 14, 'a_2': 16, 'b_0': 13, 'b_1': 15},
{'x': 2, 'y': 9, 'a_0': 22, 'a_1': 24, 'b_0': 23, 'b_1': 25, 'b_2': 27}]
(注意顺序变了)
你的要求有点棘手,但我会尽力的。 让我们继续,
所以我的方法是使用函数(定义)
def get_new(l):
N = l.copy()
for a in range(len(N)):
for b in N[a].keys():
if b in ['a','b']:
i = 1
while N[a][b]: # while N[a][b] is not empty.
key = str(b) + '_' + str(i)
i += 1
N[a][key] = N[a][b].pop(0)
del N[a][b]
return N
以上函数获取您的初始列表和return您要求的列表
字典中的函数循环及其内部键,对于每个 'a' 和 'b' 键,它将更改每个列表值的键 键像 str(a)+'_'+i
i 是完美的索引 +1
values as N[a][b][i] # 因为它每次都弹出索引 0。
删除 N[a][b] 准备好其特定键值。
我是能够想出(又是部分)列表理解式解决方案:
t = []
for obj in p:
t.append(dict([]))
[t[-1].update({key+'_'+str(i+1): val[i]
for i in range(len(obj[key]))})
if isinstance(obj[key], list) else
t[-1].update({key: val})
for key, val in zip(obj.keys(), obj.values())
]
p
中项目 (obj
) 的一个显式循环,其中在循环内创建一个新字典,并根据项目值是否向其中添加术语是不是列表...感谢我之前的回答者指出 isinstance(obj, type)
函数。
所以,打印 t
得到:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8},
{'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]
一个不值得骄傲的 这个解决方案的优点是:它不使用 f'{key}_{i+1}'
功能(虽然两个优雅的求解器都使用过,对我来说似乎有点晦涩——原谅我的无知)!
您可以使用列表理解:
p = [{'x': 1, 'a': [12, 14, 16], 'b': [13, 15], 'y': 8}, {'x': 2, 'a': [22, 24], 'b': [23, 25, 27], 'y': 9}]
r = [{a if not isinstance(b, list) else f'{a}_{l}':b if not isinstance(b, list) else j
for a, b in i.items() for l, j in enumerate((b if isinstance(b, list) else [b]), 1)}
for i in p]
输出:
[{'x': 1, 'a_1': 12, 'a_2': 14, 'a_3': 16, 'b_1': 13, 'b_2': 15, 'y': 8}, {'x': 2, 'a_1': 22, 'a_2': 24, 'b_1': 23, 'b_2': 25, 'b_3': 27, 'y': 9}]