仅给出子列表的数量长度可变,显示列表的所有可能分组

问题描述

:我发现想将列表分成几类的最简单方法是尝试获得分割位置的组合。这是一个实现:

def split_list(data, n):
    from itertools import combinations, chain
    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

>>> list(split_list([1, 2, 3, 4], 2))
[[[1], [2, 3, 4]], [[1, 2], [3, 4]], [[1, 2, 3], [4]]]
>>> list(split_list([1, 2, 3, 4], 3))
[[[1], [2], [3, 4]], [[1], [2, 3], [4]], [[1, 2], [3], [4]]]

:首先,你需要转换就像一个列表[[1], [2, 3, 4]]一个[1, 234]。您可以使用以下功能执行此操作:

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

>>> map(list_to_int, [[1], [2, 3], [4, 5, 6]])
[1, 23, 456]

现在,您可以使用reduce()以下命令在结果列表上执行操作:

>>> import operator
>>> reduce(operator.add, [1, 23, 456])  # or int.__add__ instead of operator.add
480

基于不同操作员的编辑引用需求:

def op_iter_reduce(ops, values):
    op_dict = {'+': int.__add__, '-': int.__sub__,
               '*': int.__mul__, '/': int.__div__}
    op_iter = lambda a, (i, b): op_dict[ops[i]](a, b)
    return reduce(op_iter, enumerate(values[1:]), values[0])

def group_and_map(data, num_groups):
    from itertools import combinations_with_replacement
    op_dict = {'+': int.__add__, '-': int.__sub__,
               '*': int.__mul__, '/': int.__div__}
    template = ['']*(num_groups*2 - 1) + ['=', '']
    op_iter = lambda a, (i, b): op_dict[ops[i]](a, b)
    for groups in split_list(data, num_groups):
        ints = map(list_to_int, groups)
        template[:-2:2] = map(str, ints)
        for ops in combinations_with_replacement('+-*/', num_groups-1):
            template[1:-2:2] = ops
            template[-1] = str(op_iter_reduce(ops, ints))
            print ' '.join(template)

>>> group_and_map([1, 2, 3, 4], 2)
1 + 234 = 235
1 - 234 = -233
1 * 234 = 234
1 / 234 = 0
12 + 34 = 46
12 - 34 = -22
12 * 34 = 408
12 / 34 = 0
123 + 4 = 127
123 - 4 = 119
123 * 4 = 492
123 / 4 = 30

如果您使用的是Python 2.6或更低版本,itertools.combinations_with_replacement()并且不可用,则可以使用此处链接的配方。

解决方法

问题

步骤1 :给定数字列表,仅给定所需组的最终数量,生成所有可能的分组(按顺序)。

例如,如果我的数字列表是1到4,并且我想要2个最终组,则可能是:

[1],[2,3,4]

[1,2],[3,2,3],[4]

步骤2 :对这些组执行算术运算。

例如,如果我们选择加法,则最终结果将是:

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

先验研究和类似问题

我已经在SO和其他地方看到了许多有关涉及可变 数量 组的问题的示例,这些问题利用范围和for循环,例如:

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

但这与我想要的相反-在那里,组的长度固定,最后一个组除外,并且组的数量振荡。

这不是家庭作业,只是我遇到的一个有趣的问题。理想情况下,我需要能够遍历那些单独的子列表以执行数学运算,因此也需要捕获它们。

我有一个解决方案将涉及itertools的感觉,但我似乎无法弄清楚组合方面的组合。

编辑/扩展步骤2

如果要在每个分区上执行 不同的 操作,是否仍可以采用相同的方法?而不是仅指定int。 添加
,我能以某种方式执行所有主要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)