Bre*_*ard 12 python math grouping list
步骤1:给定一个数字列表,仅给出所需组的最终数量,生成所有可能的分组(按顺序).
例如,如果我的数字列表是1到4,并且我想要2个最终组,则可能性为:
[1], [2,3,4]
[1,2], [3,4]
[1,2,3], [4]
Run Code Online (Sandbox Code Playgroud)
第2步:对这些组执行算术运算.
例如,如果我们选择添加,最终结果将是:
1 + 234 = 235
12 + 34 = 46
123 + 4 = 127
Run Code Online (Sandbox Code Playgroud)
先前的研究和类似的问题
我已经在SO和其他地方看到了很多关于涉及可变数量的组的问题的例子,它们使用范围和for循环,a la:
print [num_list[i:i+groups] for i in range(0,len(num_list),groups)]
Run Code Online (Sandbox Code Playgroud)
但这与我想要的相反 - 在那里,除了最后一组之外,组本身的长度是固定的,并且组的数量是振荡的.
这不是家庭作业,只是我遇到的一个有趣的问题.理想情况下,我需要能够迭代这些单独的子列表以执行数学运算,因此它们也需要被捕获.
我有一种感觉,解决方案将涉及itertools,但我似乎无法弄清楚组合方面的组合.
编辑/扩展第2步
如果我想在每个分区上执行不同的操作,我仍然可以采用相同的方法吗?而不是仅仅指定int.添加,我能以某种方式执行所有主要4个操作的另一个组合吗?即:
symbol_list = ['+','-','*','/']
for op in symbol_list:
#something
Run Code Online (Sandbox Code Playgroud)
我最终会有以下可能性:
1 + 2 * 34
1 * 2 - 34
1 / 2 + 34
etc.
Run Code Online (Sandbox Code Playgroud)
操作顺序可以忽略.
#!/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)
Run Code Online (Sandbox Code Playgroud)
Raymond Hettinger编写了一个配方,用于查找可迭代的所有分区n:
import itertools
import operator
def partition_indices(length, groups, chain = itertools.chain):
first, middle, last = [0], range(1, length), [length]
for div in itertools.combinations(middle, groups-1):
yield tuple(itertools.izip(chain(first, div), chain(div, last)))
def partition_into_n_groups(iterable, groups, chain = itertools.chain):
# http://code.activestate.com/recipes/576795/
# author: Raymond Hettinger
# In [1]: list(partition_into_n_groups('abcd',2))
# Out[1]: [('a', 'bcd'), ('ab', 'cd'), ('abc', 'd')]
s = iterable if hasattr(iterable, '__getitem__') else tuple(iterable)
for indices in partition_indices(len(s), groups, chain):
yield tuple(s[slice(*x)] for x in indices)
def equations(iterable, groups):
operators = (operator.add, operator.sub, operator.mul, operator.truediv)
strfop = dict(zip(operators,'+-*/'))
for partition in partition_into_n_groups(iterable, groups):
nums_list = [int(''.join(map(str,item))) for item in partition]
op_groups = itertools.product(operators, repeat = groups-1)
for op_group in op_groups:
nums = iter(nums_list)
result = next(nums)
expr = [result]
for op in op_group:
num = next(nums)
result = op(result, num)
expr.extend((op, num))
expr = ' '.join(strfop.get(item,str(item)) for item in expr)
yield '{e} = {r}'.format(e = expr, r = result)
for eq in equations(range(1,5), groups = 2):
print(eq)
Run Code Online (Sandbox Code Playgroud)
产量
1 + 234 = 235
1 - 234 = -233
1 * 234 = 234
1 / 234 = 0.0042735042735
12 + 34 = 46
12 - 34 = -22
12 * 34 = 408
12 / 34 = 0.352941176471
123 + 4 = 127
123 - 4 = 119
123 * 4 = 492
123 / 4 = 30.75
Run Code Online (Sandbox Code Playgroud)
第1步:我发现想到将列表拆分成这样的组的最简单方法是尝试获取拆分位置的组合.这是一个实现:
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]]]
Run Code Online (Sandbox Code Playgroud)
第2步:首先,你需要转换列表一样[[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]
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用reduce()以下命令在结果列表上执行操作:
>>> import operator
>>> reduce(operator.add, [1, 23, 456]) # or int.__add__ instead of operator.add
480
Run Code Online (Sandbox Code Playgroud)
完整的解决方案:基于不同运营商的编辑参考需求:
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
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Python 2.6或更低版本且itertools.combinations_with_replacement()无法使用,则可以使用此处链接的配方.
步骤1:
我研究了所有可能的索引组合:
from itertools import combinations
def cut(lst, indexes):
last = 0
for i in indexes:
yield lst[last:i]
last = i
yield lst[last:]
def generate(lst, n):
for indexes in combinations(list(range(1,len(lst))), n - 1):
yield list(cut(lst, indexes))
Run Code Online (Sandbox Code Playgroud)
例子:
for g in generate([1, 2, 3, 4, 5], 3):
print(g)
"""
[[1], [2], [3, 4, 5]]
[[1], [2, 3], [4, 5]]
[[1], [2, 3, 4], [5]]
[[1, 2], [3], [4, 5]]
[[1, 2], [3, 4], [5]]
[[1, 2, 3], [4], [5]]
"""
Run Code Online (Sandbox Code Playgroud)
第2步:
首先我们必须将数字组转换为数字:
for g in generate(list(range(1,6)), 3):
print([int(''.join(str(n) for n in n_lst)) for n_lst in g])
"""
[1, 2, 345]
[1, 23, 45]
[1, 234, 5]
[12, 3, 45]
[12, 34, 5]
[123, 4, 5]
"""
Run Code Online (Sandbox Code Playgroud)
然后reduce执行operator算术:(
尽管最后一个子步骤与您的问题并不真正相关)
from functools import reduce
import operator
op = operator.mul
for g in generate(list(range(1,6)), 3):
converted = [int(''.join(str(n) for n in n_lst)) for n_lst in g]
print(reduce(op, converted))
"""
690
1035
1170
1620
2040
2460
"""
Run Code Online (Sandbox Code Playgroud)