【问题标题】:Converting dict of lists into list of dicts将列表的字典转换为字典列表
【发布时间】:2021-02-11 21:30:24
【问题描述】:

我有一本这样的字典:

{
    "var1": [0, 1],
    "var2": ["foo", "bar"]
}

鉴于上述情况,我想最终得到一个字典列表,如下所示:

[
    { "var1_0_var2_foo": {"var1": 0, "var2": "foo"} },
    { "var1_1_var2_bar": {"var1": 1, "var2": "bar"} }
]

原始字典中每个列表中的键和元素的数量是可变的,可以是任何东西。

这是我看起来凌乱但有效的解决方案:

source = {
    'x': ['a', 'b'],
    'y': [0, 1],
    'z': ['foo', 'bar']
}

target = []


names = list(source.keys())
lists = list(source.values())
zipped = list(zip(*lists))

for item in zipped:
    full_name = ""
    full_dict = {}
    for idx, value in enumerate(item):
        full_name += f"{names[idx]}_{value}_"
        full_dict[names[idx]] = value
    full_name = full_name.rstrip('_')
    target.append({full_name: full_dict})

print(target)

输出:

[
    {'x_a_y_0_z_foo': {'x': 'a', 'y': 0, 'z': 'foo'}}, 
    {'x_b_y_1_z_bar': {'x': 'b', 'y': 1, 'z': 'bar'}}
]

上述方法可行,但我想知道是否有更好的优雅 Python 方式来执行此操作?

【问题讨论】:

  • 想要以字典列表结尾 您提供的列表无效,因为它具有字典声明语法(您指定的 var1_0_var2_foo: 仅在 dict s)
  • 请使用有效代码编辑您的问题。
  • 抱歉,语法固定。

标签: python list dictionary zip


【解决方案1】:
from itertools import chain

spam = {'x': ['a', 'b'],
        'y': [0, 1],
        'z': ['foo', 'bar']}

eggs = []
for item in zip(*spam.values()):
    key = '_'.join(chain(*zip(spam.keys(), map(str, item))))
    eggs.append({key:dict(zip(spam.keys(), item))})

print(eggs)

输出

[{'x_a_y_0_z_foo': {'x': 'a', 'y': 0, 'z': 'foo'}},
 {'x_b_y_1_z_bar': {'x': 'b', 'y': 1, 'z': 'bar'}}]

【讨论】:

  • 应该想到链条,是的。感谢分享答案!
【解决方案2】:

这是使用列表推导和 lambda 函数执行此操作的 Pythonic 方式 -

d = {
    'x': ['a', 'b'],
    'y': [0, 1],
    'z': ['foo', 'bar']
}

f = lambda x: {i:j for i,j in zip(d,x)}  #Creates the values of final output
g = lambda x: '_'.join([str(j) for i in zip(d,x) for j in i])  #Creates the keys of final output

target = [{g(i):f(i)} for i in zip(*d.values())]
print(target)
[{'x_a_y_0_z_foo': {'x': 'a', 'y': 0, 'z': 'foo'}},
 {'x_b_y_1_z_bar': {'x': 'b', 'y': 1, 'z': 'bar'}}]

【讨论】:

  • 选择这个作为答案,因为它避免了任何导入!很棒的代码。
  • 很高兴随时提供帮助。
  • 讽刺的是,当代码违反 PEP8 建议时,以 Here is pythonic way 开头:始终使用 def 语句而不是绑定 lambda 的赋值语句表达式直接到标识符。第一种形式意味着生成的函数对象的名称是专门的“f”而不是通用的“”。这对于一般的回溯和字符串表示更有用。赋值语句的使用消除了 lambda 表达式相对于显式 def 语句所能提供的唯一好处(即它可以嵌入到更大的表达式中)
  • 讽刺的是,引用 PEP8,当第一段本身明确声明:正如 PEP 20 所说,“可读性很重要”。风格指南是关于一致性的。与本风格指南保持一致很重要。项目内部的一致性更为重要。一个模块或功能内的一致性是最重要的。但是,知道什么时候不一致——有时风格指南建议不适用。如有疑问,请使用您的最佳判断。 抱歉并不意味着无礼 :)
  • 虽然我确实知道您来自哪里,但从可读性的角度来看,我更喜欢使用 lambda 函数进行 1 班轮返回。我一开始把所有的代码都塞进了一行,但那看起来很糟糕!
【解决方案3】:

我不明白输出列表中外部字典的原因是什么,为什么不只是一个字典输出列表:

data = {
'var1': [0, 1],
'var2': ["foo", "bar"]}

output = [dict(zip(data, vars)) for vars in zip(*data.values())]

[{'var1': 0, 'var2': 'foo'}, {'var1': 1, 'var2': 'bar'}]

【讨论】:

  • 可能不是 OP 要求的,但显然是将原始字典转换为列表的更合乎逻辑的方式。 “预期输出”中的键意义不大,不太可能有任何用处。也许寻找 OP 正在寻找一种文件名模式来存储 JSON 数据?
  • 正确,如果不需要那个愚蠢的键名,那将是一个更简单的问题。我出于某种不可避免的原因需要钥匙。
猜你喜欢
  • 2017-04-23
  • 2021-10-13
  • 2018-08-21
  • 1970-01-01
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多