Python 将包含列表项的dict展开为dict对列表
如果我有一个字典,其中包含一个或多个值中的列表:Python 将包含列表项的dict展开为dict对列表,python,python-2.7,dictionary,list-comprehension,dictionary-comprehension,Python,Python 2.7,Dictionary,List Comprehension,Dictionary Comprehension,如果我有一个字典,其中包含一个或多个值中的列表: data = { 'a':0, 'b':1, 'c':[0, 1, 2], 'pair':['one','two'] } 我如何获得一个dict元组列表,该列表由pair配对,并在c上迭代,而所有其他元组保持不变?例如 output = [ ({ 'a':0, 'b':1, 'c':0, 'pair':'one' }, { '
data = {
'a':0,
'b':1,
'c':[0, 1, 2],
'pair':['one','two']
}
我如何获得一个dict元组列表,该列表由pair
配对,并在c
上迭代,而所有其他元组保持不变?例如
output = [
({
'a':0,
'b':1,
'c':0,
'pair':'one'
},
{
'a':0,
'b':1,
'c':0,
'pair':'two'
}),
({
'a':0,
'b':1,
'c':1,
'pair':'one'
},
...
]
这感觉不是特别优雅,但您可以使用嵌套的for循环或列表理解:
output = []
for i in data['c']:
output.append(tuple({'a': 0, 'b': 1, 'c': i, 'pair': p} for p in data))
或
更干净的解决方案可能会将组件dict的生成分离为一个函数,如下所示:
def gen_output_dict(c, pair):
return {'a': 0, 'b': 1, 'c': c, 'pair': pair}
output = []
for i in data['c']:
output.append(tuple(gen_output_dict(i, p) for p in data['pair']))
您可以对列表值使用
itertools.product
,并跟踪每个元素起源的键。由于密钥'pair'
具有特殊含义,因此应单独处理
代码
例子
输出
您可以使用
itertools
:
import itertools
data = {
'a':0,
'b':1,
'c':[0, 1, 2],
'pair':['one','two']
}
def expand_dict(data):
grouped = [a for a, b in data.items() if isinstance(b, list)]
p = [[a, list(b)] for a, b in itertools.groupby(itertools.product(*[data[i] for i in grouped]), key=lambda x:x[0])]
return [tuple({**data, **dict(zip(grouped, i))} for i in c) for _, c in p]
print(expand_dict(data))
输出:
[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
({'a': 0, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]
[({'a': 5, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 6, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 1, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 3, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'two'})]
此解决方案还可用于具有许多可能的值列表的输入:
data = {'a':[5, 6, 1, 3], 'b':1, 'c':[0, 1, 2], 'pair':['one', 'two']}
print(expand_dict(data))
输出:
[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
({'a': 0, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]
[({'a': 5, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 5, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 6, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 6, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 1, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 1, 'b': 1, 'c': 2, 'pair': 'two'}), ({'a': 3, 'b': 1, 'c': 0, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 0, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 1, 'pair': 'two'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'one'}, {'a': 3, 'b': 1, 'c': 2, 'pair': 'two'})]
以下是一个相当扩展的解决方案:
data = {
'a':0,
'b':1,
'c':[0, 1, 2],
'pair':['one','two']
}
# Get the length of the longest sequence
length = max(map(lambda x: len(x) if isinstance(x, list) else 1, data.values()))
# Loop through the data and change scalars to sequences
# while also making sure that smaller sequences are stretched to match
# or exceed the length of the longest sequence
for k, v in data.items():
if isinstance(v, list):
data[k] = v * int(round(length/len(v), 0))
else:
data[k] = [v] * length
# Create a dictionary to keep track of which outputs
# need to end up in which tuple
seen = dict.fromkeys(data.get('pair'), 0)
output = [tuple()] * len(seen)
# Loop through the data and place dictionaries in their
# corresponding tuples.
for v in zip(*data.values()):
d = dict(zip(data, v))
output[seen[d.get('pair')]] += (d,)
seen[d.get('pair')] += 1
print(output)
其思想是将数据中的标量转换为长度与原始数据中最长序列长度匹配的序列。因此,我做的第一件事就是将最长序列的大小分配给变量length
。有了这些知识,我们在将标量转换为序列的同时,循环遍历原始数据并扩展现有序列以匹配最长序列的大小。
完成后,我们开始生成输出
变量。但首先,我们创建一个名为seen
的字典,以帮助我们创建元组列表,并跟踪哪组字典最终位于哪个元组中。
这样,我们就可以运行最后一个循环,将字典组放到相应的元组中
当前输出如下所示:
[({'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
{'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
({'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},)]
请让我知道,如果你需要任何更多的澄清细节。否则,我真的希望这能起到一些作用。不太完美,但这是我的解决方案。
@r3robertson,您也可以尝试以下代码。代码基于Python中的
列表理解
,&deepcopy()操作
的概念
检查
输出»
[ ( { 'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 1, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]
[
[
{
"a": 0,
"c": 0,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 0,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 1,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 1,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 2,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 2,
"b": 1,
"pair": "two"
}
]
]
使用json模块进行漂亮打印»
注意:元组将在此处转换为列表,因为JSON中不支持元组
输出»
[ ( { 'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 1, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]
[
[
{
"a": 0,
"c": 0,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 0,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 1,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 1,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 2,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 2,
"b": 1,
"pair": "two"
}
]
]
如果OP有大量的键和值,他必须遍历整个字典,找到键,该值是列表的一种类型。你知道@U8转发的是什么,你可能是对的,OP询问的是一个更一般的列表迭代情况。这也是我的本能,但后来我注意到,它们需要根据
pair
key的值(实际上,基于c
keys的值)在列表中对元组中的项进行配对。您仍然可以使用itertools产品,但它的通用性会差一点。@jedwards有一个UDD版本,多亏了它的帮助。op需要一个dict元组列表,该列表是成对的,并在c上迭代,但您的脚本通过随机键(data.items()
)配对,并在other@bobrobbob是,但是,请注意[数据[i]对于分组中的i]
。虽然data.items()
是随机的,[data[i]for i in grouped]
将按照data.items()
创建的顺序查找数据值。此有效配对仍然使用zip(grouped,i)
进行维护。可能我错误地识别了随机输出的原因,但它仍然是随机的。我不认为你可以避免硬编码这里为什么c
1
的最后一个元素是2
?@user3483203有一个省略号,你事先知道要“扩展”的值的键吗?我是否正确地理解了,结果列表类似于扩展值的笛卡尔积?您对扩展dict的想法将是一个有趣的问题。这个问题特别是关于获得给定起始dict的“dict元组列表,该列表由pair
配对,并在c
上迭代,其他所有元组保持不变”。老实说,我认为您想尝试用错误的解决方案解决问题。可能会发布输入和期望的结果,并描述问题区域。
[ ( { 'a': 0, 'b': 1, 'c': 0, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 0, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 1, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 1, 'pair': 'two'}),
( { 'a': 0, 'b': 1, 'c': 2, 'pair': 'one'},
{ 'a': 0, 'b': 1, 'c': 2, 'pair': 'two'})]
import json;
print(json.dumps(output, indent=4));
[
[
{
"a": 0,
"c": 0,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 0,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 1,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 1,
"b": 1,
"pair": "two"
}
],
[
{
"a": 0,
"c": 2,
"b": 1,
"pair": "one"
},
{
"a": 0,
"c": 2,
"b": 1,
"pair": "two"
}
]
]