【问题标题】:dictionary of values/lists to list of dictionaries值/列表字典到字典列表
【发布时间】:2021-07-13 11:56:07
【问题描述】:

给定一个字典,其中包含不同长度的列表,但不仅如此,例如

d = {foo: 'hello', bar: [0, 2], baz: [1, 2, 3]}

我想创建一个所有可能组合的列表,其中每个组合都是一个字典:

l = [{foo: 'hello', bar: 0, baz: 1},
     {foo: 'hello', bar: 0, baz: 2},
     {foo: 'hello', bar: 0, baz: 3},
     {foo: 'hello', bar: 2, baz: 1},
     {foo: 'hello', bar: 2, baz: 2},
     {foo: 'hello', bar: 2, baz: 3}]

这里的顺序无关紧要,我不需要将列表转换回字典。

当然可以使用 Python 循环执行此操作,但我正在寻找更高效和/或更优雅的解决方案。

【问题讨论】:

  • foo 与 bar 和 baz 有什么不同?因为那是唯一不是列表的元素。
  • 确实,foo 不是一个列表。但是,如果仅使用列表更简单,那对我来说没问题。

标签: python-3.x


【解决方案1】:

Itertools 非常适合这个。代码可能如下所示:

import itertools

d = {'foo': 'hello', 'bar': [0, 2], 'baz': [1, 2, 3]}
a = [list(x) for x in d.values() if isinstance(x, list)]
constant_values = [x for x in d.values() if x not in a]
keys = d.keys()

combinations = list(itertools.product(*a))

使用常量值和键将其转换为字典作为最后一步

【讨论】:

  • 组合:[(0, 1), (0, 2), (0, 3), (2, 1), (2, 2), (2, 3)]
  • 其实把'hello'改成['hello']就可以了。但是这里不能放开这个约束,保持'hello'不变吗?
  • 此外,它返回元组列表而不是字典列表。所有键都丢失了,我不知道如何“将其转换为字典作为最后一步”。
  • 我使用从 DSteman 的回答中推导出的可能算法编辑了我的问题(谢谢),但我很确定这不是一个非常聪明的实现。
  • 我的代码输出的元组分别对应bar和baz的值。 On tuple 有两个值,因为 foo 不是列表,因此不包含多个值,因此在查找所有组合时不需要考虑。
【解决方案2】:

我觉得@DSteman 的回答基本上是正确的,他们为您提供了解决问题所需的工具。

鉴于他们出色的起步建议,我发现您一直在纠结如何完成比赛。所以这里有一个更简单、更明确的版本,它缺乏它们所包含的灵活性,但直接产生了你想要的结果。

如果您认为这可以解决您的问题,我强烈建议您重新查看他们的答案并将其视为“解决方案”。

import itertools

data_in = {"foo": "hello", "bar": [0, 2], "baz": [1, 2, 3]}
data_out = [
    {"foo": data_in["foo"], "bar": c[0], "baz": c[1]}
    for c in itertools.product(data_in["bar"], data_in["baz"])
]

print(data_out)

这将产生:

[
    {'foo': 'hello', 'bar': 0, 'baz': 1},
    {'foo': 'hello', 'bar': 0, 'baz': 2},
    {'foo': 'hello', 'bar': 0, 'baz': 3},
    {'foo': 'hello', 'bar': 2, 'baz': 1},
    {'foo': 'hello', 'bar': 2, 'baz': 2},
    {'foo': 'hello', 'bar': 2, 'baz': 3}
]

【讨论】:

  • 谢谢 JonSG。您非常有趣的答案的主要缺点是它依赖于输入字典将具有与作为示例给出的字典相同的结构的假设。因此,它不如我从 DSteman 的答案中推断出的答案一般,尽管您自己的答案比我的要优雅得多。
【解决方案3】:

下面的算法以通用的方式回答了这个问题:

def list_of_dictionaries(self, dictionary):
  # values which are not lists are forced to be lists
  for k, v in dictionary.items():
    if type(v) is not list:
        dictionary[k] = [v]

  # list all combinations of values
  combinations = [list(x) for x in dictionary.values() if isinstance(x, list)]
  combinations = list(itertools.product(*combinations))

  # create list of dictionaries
  list_of_dicts = []
  for values in combinations:
    dict_element = {}
    for i, k in enumerate(dictionary.keys()):
        dict_element[k] = values[i]
    list_of_dicts.append(dict_element)

  return list_of_dicts

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 2011-07-30
    • 1970-01-01
    相关资源
    最近更新 更多