Показать все возможные группировки списка, учитывая только количество подсписок (длина варьируется)

Проблема

Шаг 1 : Учитывая список чисел, сгенерируйте все возможные группировки (по порядку) с учетом только окончательное количество желаемых групп.

Например, если бы в моем списке чисел было от 1 до 4, и я хотел бы две заключительные группы, возможны были бы следующие варианты:

[1], [2,3,4]

[1,2], [3,4]

[1,2,3], [4]

Шаг 2 : Выполните арифметические операции с этими группами.

Например, если мы выберем сложение, окончательные результаты будут такими:

1 + 234 = 235
12 + 34 = 46
123 + 4 = 127

Предыдущие исследования и аналогичные проблемы

Я видел множество примеров на SO и в других местах для проблем, связанных с переменными количествами группы, которые используют диапазоны и циклы, а-ля:

print [num_list[i:i+groups] for i in range(0,len(num_list),groups)]

Но это своего рода обратное тому, что я хочу - здесь длины самих групп фиксированы, за исключением последней, а количество групп колеблется.

Это не домашнее задание, просто интересная проблема, с которой я столкнулся. В идеале мне нужно было бы иметь возможность перебирать эти отдельные подсписки, чтобы выполнять математические операции, поэтому их также нужно будет фиксировать.

Я чувствую, что решение будет включать в себя itertools, но я не могу понять комбинаторику с аспектом группирования.

Редактирование / расширение шага 2

Если я хочу выполнить различных операций на каждом из разделов, могу ли я подойти к этому так же? Вместо того, чтобы указывать просто int. add , можно как-нибудь выполнить еще одну комбинацию всех основных 4 операций? То есть:

symbol_list = ['+','-','*','/']
for op in symbol_list:
   #something

Я бы столкнулся с возможностями:

1 + 2 * 34
1 * 2 - 34
1 / 2 + 34
etc.

Порядок операций можно игнорировать .

Окончательное решение

#!/usr/bin/env python

import sys
from itertools import combinations, chain, product

# fixed vars
num_list = range(_,_) # the initial list
groups = _ # number of groups
target = _ # any target desired
op_dict = {'+': int.__add__, '-': int.__sub__,
           '*': int.__mul__, '/': int.__div__}

def op_iter_reduce(ops, values):
    op_iter = lambda a, (i, b): op_dict[ops[i]](a, b)
    return reduce(op_iter, enumerate(values[1:]), values[0])

def split_list(data, n):
    for splits in combinations(range(1, len(data)), n-1):
        result = []
        prev = None
        for split in chain(splits, [None]):
            result.append(data[prev:split])
            prev = split
        yield result

def list_to_int(data):
    result = 0
    for h, v in enumerate(reversed(data)):
        result += 10**h * v
    return result

def group_and_map(data, num_groups):
    template = ['']*(num_groups*2 - 1) + ['=', '']
    for groups in split_list(data, num_groups):
        ints = map(list_to_int, groups)
        template[:-2:2] = map(str, ints)
        for ops in product('+-*/', repeat=num_groups-1):
            template[1:-2:2] = ops
            template[-1] = str(op_iter_reduce(ops, ints))
            if op_iter_reduce(ops, ints) == target:
                print ' '.join(template)

group_and_map(num_list, groups)
12
задан Martin Thoma 16 April 2016 в 16:41
поделиться