【问题标题】:All possible combinations of elements from sets of different sizes来自不同尺寸集合的元素的所有可能组合
【发布时间】:2019-09-06 09:27:27
【问题描述】:

我正在创建一个供我私人使用的工具,但遇到了一个复杂的组合问题。

我有 7 个类似格式的子字典:

{"D1": {"A": 1, "B": 3, "C":6},
 "D2": {"D": 4},
 "D3": {"E": 8, "F": 12, "G": 2}.
 "D4": {"H": 9, "I": 3}.
 "D5": {"J": 2},
 "D6": {"K": 8, "L": 1},
 "D7": {"M": 2}}

我需要的是生成所有可能的字典,这些字典将以这种格式从每个字典中组合 1 个元素:

[{"D1": "A", "D2": "D", "D3": "E", "D4": "H", "D5": "J", "D6": "K", "D7": "M"},
 {"D1": "A", "D2": "D", "D3": "F", "D4": "I", "D5": "J", "D6": "L", "D7": "M"},
 and all other possible combinations]

输出应该是所有 DX 字典中元素的所有可能唯一组合的列表。 我可能能够使用一些非常复杂、外观丑陋、带有大量 if 的嵌套 for 循环来解决这个问题,但可能有一种非常好的方法可以在 itertools 或类似的东西中实现它。

对高效完成这项任务有什么帮助吗? 这个任务需要在大量这样的字典上重复,所以性能是关键。 谢谢!

【问题讨论】:

  • 棘手的(并且可能不可避免地难看)位是将"D1"globals中取出;剩下的很简单itertools工作
  • 实际上有一个看起来像这样的字典列表: [{D1: ..., D2: ... D3: ...}, {D11: ..., D22: .. ., ...}, ...]。
  • 而您只想要这些特别突出的那些?因为他们的名字?
  • 嗯,我猜这个问题表述得不够清楚。让我重做它:)

标签: python dictionary itertools


【解决方案1】:

看起来有点复杂,但是一个相当简单的解决方案:

import itertools

D = [D1, D2, D3, D4, ...]

dicts = [
    dict(zip([f'D{i+1}' for i in range(len(D))], iter)) 
    for iter in itertools.product(*[list(d.keys()) for d in D])
]

dict_1 = dicts[0]
dict_2 = dicts[1]
...
dicts = [
    {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'H'},
    {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'I'},
    {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'H'},
    {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'I'},
    ...
]

工作原理:

生成所有键组合

itertools.product(*[list(d.keys()) for d in D])

将组合与适当的字典名称组合起来

zip([f'D{i+1}' for i in range(len(D))], iter))

将这两个部分组合起来,并将它们分别转换为字典

[
    dict(zip([f'D{i+1}' for i in range(len(D))], iter)) 
    for iter in itertools.product(*[list(d.keys()) for d in D])
]

【讨论】:

  • 完美!我可以用它! :) itertools 问题对我来说太难了。我需要更好地学习 itertools!
  • 很高兴听到。我意识到我没有在解决方案中添加 D,更新了答案。
【解决方案2】:

您想要的是字典的笛卡尔积。 幸运的是,itertools 定义了一个 product 函数来做这件事。

当用作可迭代对象时,dict 将产生其键,因此 product(D1, D2, ...) 将直接产生键元组,例如 ('A', 'D', 'F', ...)

您需要进行一些调整才能获得所需的准确输出:

from pprint import pprint
import itertools

dicts = [
    {"A": 1, "B": 3, "C":6},
    {"D": 4},
    {"E": 8, "F": 12, "G": 2},
    {"H": 9, "I": 3}
]

r = [
    {f"D{i}": key for i, key in enumerate(x, 1)}
    for x in itertools.product(*dicts)
]
pprint(r)

输出:

[{'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'H'},
 {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'I'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'H'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'I'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'H'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'I'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'H'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'I'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'H'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'I'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'H'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'I'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'H'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'I'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'H'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'I'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'H'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'I'}]

【讨论】:

  • 了不起的家伙!非常感谢!
  • @StarTrekFan 不客气!花一些时间更深入地学习itertools,并看看惊人的more_itertools :)
【解决方案3】:

itertools product是你的朋友:

from itertools import product

d = {"D1": {"A": 1, "B": 3, "C":6}, 
     "D2": {"D": 4},  
     "D3": {"E": 8, "F": 12, "G": 2}, 
     "D4": {"H": 9, "I": 3}, 
     "D5": {"J": 2}, 
     "D6": {"K": 8, "L": 1}, 
     "D7": {"M": 2}}

res = []
for c in product(*(v.keys() for _, v in d.items())):
  res.append(dict(zip(d.keys(), c)))

列表理解版本是:

res = [dict(zip(d.keys(), c)) for c in product(*(v.keys() for _, v in d.items()))]

产生:

[{'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'A', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'B', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'E', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'F', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'H', 'D5': 'J', 'D6': 'L', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'K', 'D7': 'M'},
 {'D1': 'C', 'D2': 'D', 'D3': 'G', 'D4': 'I', 'D5': 'J', 'D6': 'L', 'D7': 'M'}]

优点和缺点

(+) 与其他答案不同,这个答案不依赖于 D<i> 模式之后的子目录的命名;它们可以被称为任何东西。

(-) 必须保留字典的顺序,因此您需要 Python 3.5+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多