Используйте рекурсию в Python для объединения списков переменных размеров - PullRequest
0 голосов
/ 01 июня 2018

У меня есть проблема с проблемой, которая стала немного проблемной по мере возникновения проблем.

ситуация:

Мне нужно объединить элементы в списке (списках) переменных размеров с переменнойэлементы размера, сохраняйте эти комбинации и затем просматривайте их.Я попробовал itertools, но я получаю слишком много комбинаций, которые я не знаю, как правильно «очистить».Я получаю правильные комбинации, просто создав столько циклов for, сколько элементов op в списке ввода.

пример: ПРИМЕЧАНИЕ. Количество словарей op может отличаться!Игнорируйте значения как таковые, важно то, что я использую список словарей "op", чтобы в основном получить все пользовательские элементы управления в элементе Nuke GUI, называемом NoOp node.Мне нужно перебрать каждый из элементов управления для каждого значения, составив все возможные комбинации:

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, этот сценарий просто рекурсивно печатает элементы управления

Как использовать рекурсию для этого случая, и, что более важно, должен ли я использовать рекурсию вообще, и если да, как мне подходить к такому случаюи разбить его на составляющие?Cheers,

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Абсолютно вы должны использовать рекурсию:

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, "")
0 голосов
/ 01 июня 2018

Вот способ печати всех комбинаций в три этапа:

  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

В качестве альтернативы, все возможные комбинации могут быть перечислены более компактно путем объединения различных операционных мнений:

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']}
0 голосов
/ 01 июня 2018

Не на 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'))]
...