【问题标题】:Use recursion in python to combine lists of variable sizes在 python 中使用递归来组合可变大小的列表
【发布时间】:2018-11-11 08:09:27
【问题描述】:

我有一个问题,随着问题的发展,这有点问题。

情况:

我需要将可变大小的列表中的项目与可变大小的元素组合在一起,存储这些组合,然后遍历它们。我尝试了 itertools,但我得到了太多的组合,我不知道如何正确“清理”。 通过创建与输入列表中“op”元素的数量一样多的 for 循环,我得到了正确的组合。

示例: 注意:“op”字典的数量可能会有所不同!忽略这样的值,重要的是,我使用“op”字典列表来基本上获取 Nuke GUI 元素中称为 NoOp 节点的所有自定义控件。我需要遍历每个值的每个控件,进行所有可能的组合:

for option1 in op1["options"]:
    for option2 in op2["options"]:
        for option3 in op3["options"]:
            print op1["control"], option1, op2["control"], option2,   op3["control"], option3     

现在我只是想弄清楚如何定义基本情况:/

def getCombos(controls, n = 0):
        #combos = []
        if n == 0:
            #return [(control["control"], option) for control in controls for option in control["options"]]
            return [(item["control"], option) for item in controls for option in item["options"]]
        else:
            for control in controls:
                return(getCombos(controls, n-1))
                n -= 1


op1 = {"control": "Material", "options": ["Glass", "Metal", "Wood"]}
op2 = {"control": "Base",
       "options": ["Chrome", "Brass", "Bronce", "Gold", "Nickel", "Red Gold"]}
op3 = {"control": "Color", "options": ["Red", "Blue", "Green", "Cyan", "SomeWonderfulNewColor"]}


controls = [op1, op2, op3]
#NOTE: number of elements (dict) in list controls may vary!

for i,combo in enumerate(getCombos(controls, n=len(controls))):
    print i, combo

ATM 这个脚本只是递归地打印控件

在这种情况下如何使用递归,更重要的是,我应该使用递归吗?如果是,我该如何处理这种情况并将其分解为组件? 干杯,

【问题讨论】:

  • 虽然我喜欢介绍,但帖子缺少带有具体示例数据的minimal reproducible example。当前方法的输入、预期输出和错误输出。
  • 你想要什么样的“组合”?你试过itertools.product(opt1["options"], opt2["options"], ...)吗?
  • 也许我真的应该把元组放在前面的例子中:for option1 in op1["options"]: for option2 in op2["options"]: for option3 in op3["options"]: print ( op1["control"], option1), (op2["control"], option2), (op3["control"], option3) 我会尝试已经发布的解决方案,干杯

标签: python loops for-loop recursion iteration


【解决方案1】:

不是 100% 确定您要达到的目标,但如果您想获得所有选项组合,您应该使用itertools.product

>>> list(itertools.product(op1["options"], op2["options"], op3["options"]))
[('Glass', 'Chrome', 'Red'),
 ('Glass', 'Chrome', 'Blue'),
 ('Glass', 'Chrome', 'Green'),
 ...
 ('Wood', 'Red Gold', 'Cyan'),
 ('Wood', 'Red Gold', 'SomeWonderfulNewColor')]

如果您想将它们与各自的 control 结合起来,您可以编写一个辅助函数来获取这些对,然后获取其中的 product

>>> pairs = lambda op: [(op["control"], o) for o in op["options"]]
>>> pairs(op1)
[('Material', 'Glass'), ('Material', 'Metal'), ('Material', 'Wood')]

>>> list(itertools.product(*map(pairs, (op1, op2, op3))))
[(('Material', 'Glass'), ('Base', 'Chrome'), ('Color', 'Red')),
 (('Material', 'Glass'), ('Base', 'Chrome'), ('Color', 'Blue')),
 (('Material', 'Glass'), ('Base', 'Chrome'), ('Color', 'Green')),
 ...
 (('Material', 'Wood'), ('Base', 'Red Gold'), ('Color', 'Cyan')),
 (('Material', 'Wood'), ('Base', 'Red Gold'), ('Color', 'SomeWonderfulNewColor'))]

【讨论】:

    【解决方案2】:

    绝对应该使用递归:

    def print_all(controls, idx, combination):
        if idx == len(controls):
            print(combination)
            return
    
        for x in controls[idx]['options']:
            print_all(controls, idx+1, combination + " " + controls[idx]['control'] + " " + str(x))
    
    
    op1 = {"control": "Material", "options": ["Glass", "Metal", "Wood"]}
    op2 = {"control": "Base",
       "options": ["Chrome", "Brass", "Bronce", "Gold", "Nickel", "Red Gold"]}
    op3 = {"control": "Color", "options": ["Red", "Blue", "Green", "Cyan", "SomeWonderfulNewColor"]}
    op4 = {"control": "year", "options": [2010, 2020]}
    
    controls = [op1, op2, op3, op4]
    
    print_all(controls, 0, "")
    

    【讨论】:

    • 将代码复制到文件中,修正缩进并运行。
    • 这个解决方案对我来说看起来很优雅,如何将输出从字符串更改为对并将它们存储在列表中以供进一步使用?
    • @Klemen 你能告诉我这些对是什么样子的吗?
    • ('Material', 'Glass'), ('Base', 'Chrome'), ('Color', 'Red')), ('Material', 'Glass'), ( 'Base', 'Chrome'), ('Color', 'Blue')), ('Material', 'Glass'), ('Base', 'Chrome'), ('Color', 'Green')) , .. ('Material', 'Wood'), ('Base', 'Red Gold'), ('Color', 'Cyan')), ('Material', 'Wood'), ('Base', '红金'), ('颜色', 'SomeWonderfulNewColor'))
    • [ [('Material', 'Wood'), ('Base', 'Red Gold'), ('Color', 'Red'), ('year', '2020') ], [('材料', '木材'), ('底座', '红金'), ('颜色', '蓝色'), ('年份', '2010')], [('材料' , 'Wood'), ('Base', 'Red Gold'), ('Color', 'Blue'), ('year', '2020')] ] ???
    【解决方案3】:

    这是一种分三步打印所有组合的方法:

    1. {control: control_val, options: options_vals} 转到{control_val: options_vals}。这是由from_record 函数完成的。
    2. {control_val: options_vals} 转换为[(control_val, options_val)] 的列表。这是由iter_dict 完成的。
    3. 在所有不同的操作中获取此类列表的产品。
    4. 格式化和打印。 3 和 4 由 print_combinations 处理。

    from itertools import product
    
    
    def from_record(dct):
        return {dct["control"]: dct["options"]}
    
    
    def iter_dict(dct):
        yield from ((k, v) for k, vs in dct.items() for v in vs)
    
    
    def print_combinations(dcts):
        for item in product(*(iter_dict(from_record(dct)) for dct in dcts)):
            print(", ".join(["{}: {}".format(*t) for t in item]))
    
    
    op1 = {"control": "Material", "options": ["Glass", "Metal", "Wood"]}
    op2 = {
        "control": "Base",
        "options": ["Chrome", "Brass", "Bronce", "Gold", "Nickel", "Red Gold"],
    }
    op3 = {
        "control": "Color",
        "options": ["Red", "Blue", "Green", "Cyan", "SomeWonderfulNewColor"],
    }
    
    print_combinations([op1, op2, op3])
    
    # e.g.
    # Material: Glass, Base: Chrome, Color: Red
    # Material: Glass, Base: Chrome, Color: Blue
    # Material: Glass, Base: Chrome, Color: Green
    # Material: Glass, Base: Chrome, Color: Cyan
    # Material: Glass, Base: Chrome, Color: SomeWonderfulNewColor
    

    另外,所有可能的组合可以通过组合不同的 op dicts 更紧凑地列出:

    res = dict()
    ops = [op1, op2, op3]
    for op in ops:
        res.update(from_record(op))
    
    
    # {'Base': ['Chrome', 'Brass', 'Bronce', 'Gold', 'Nickel', 'Red Gold'],
     # 'Color': ['Red', 'Blue', 'Green', 'Cyan', 'SomeWonderfulNewColor'],
     # 'Material': ['Glass', 'Metal', 'Wood']}
    

    【讨论】:

    • 有道理。您可能应该在问题中添加您想要的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2013-06-13
    • 2021-04-22
    • 1970-01-01
    • 2020-02-06
    • 1970-01-01
    • 2010-09-17
    相关资源
    最近更新 更多