从Python中的整数列表中确定所有可能产品的列表

时间:2016-09-10 16:27:38

标签: python algorithm combinations combinatorics

在Python 2.7中,我需要一个返回json.extract! @item, :locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder] 的所有可能产品的方法。 IE浏览器。如果输入是list or tuple of int,那么我想要一个像

这样的输出
  • (2, 2, 3, 4),2 * 2 = 4
  • (3, 4, 4),2 * 3 = 6
  • (2, 4, 6),2 * 4 = 8
  • (2, 3, 8),2 * 2 = 4
  • (3, 4, 4),3 * 4 = 12
  • (2, 2, 12),2 * 3 * 4 = 24
  • (2, 24),2 * 2 * 4 = 16
  • (3, 16),2 * 2 * 3 = 12
  • (4, 12),2 * 2 * 3 * 4 = 48

包裹在(48)中。我认为使用list or tuple中的combinations可能很有可能实现,但我很感激您的帮助。请注意,我只对不同的列表感兴趣,itertools的顺序不起作用。

修改

对一些澄清的进一步解释。拿第一个输出列表。输入为int(始终)。然后我拿2和2 out 列表并将它们相乘,所以现在我留下了一个列表(2, 2, 3, 4)。输入的3和4以及产品的最后4个。

我还没有尝试任何东西,因为我无法绕过那种循环。但我不能停止思考这个问题,所以如果我得到建议,我会添加一些代码。

4 个答案:

答案 0 :(得分:1)

您的问题基本上是查找给定集的所有子集(在您的情况下为多集)。一旦你有了子集,就可以直接构建你要求的输出。

对于集合A,找到所有子集[S0,S1,...,Si]。对于每个子集Si,取(A - Si) | product(Si),其中|为union,-为集合差异。您可能对大小为0和1的子集不感兴趣,因此您可以将它们排除在外。

查找子集是一个众所周知的问题,因此我确信您可以找到有关如何执行此操作的资源。请记住,有一组具有N个元素的2 ** N个setbset。

答案 1 :(得分:0)

假设你有一个4个数字的向量(例如(2,2,3,4))。

您可以生成一个网格(如下所示):

0 0 0 0
0 0 0 1
0 0 1 0 
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

现在删除所有'0'的行和只有一个'1'的行。

0 0 1 1
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1

现在,您可以将'1'替换为向量中的相应元素。 如果你的向量是(2,2,3,4),它就变成了:

0 0 3 4
0 2 0 4
0 2 3 0
0 2 3 4
2 0 0 4
2 0 3 0
2 0 3 4
2 2 0 0
2 2 0 4
2 2 3 0
2 2 3 4

尝试在Python中实现这一点。 在伪代码下面:

for i from 0 to 2^VECTOR_LEN:
    bin=convert_to_binary(i)
    if sum_binary_digit(bin) > 1:
       print(exec_moltiplication(bin,vector) 
       # if you want you can also use the bin vector as mask for the updating 
       # of your tuple of int with the result of the product and append it
       # in a list (as in your example).
       # For example if bin is (1 1 0 0) you can edit (2 2 3 4) in (4 3 4)
       # and append (4 3 4) inside the list or if it is (1 0 1 0) you can 
       # update (2 2 3 4) in (6 2 4)

其中:

  • vector:是包含数字的向量
  • VECTOR_LEN是向量的长度
  • convert_to_binary(num)是将整数(num)转换为二进制
  • 的函数
  • sum_binary_digit(bin)是一个对二进制数(bin)中的1进行求和的函数
  • exec_multiplication(vector,bin)输入vector(vector)和binary(bin)并返回乘法值。

答案 2 :(得分:0)

我不能给你算法(因为我自己也不知道),但是有 lib 可以完成这个任务...... 看看你给定的输入数字,它们似乎是因子,所以如果我们将所有这些因子相乘,我们得到一个数字(比如 x),现在使用 sympy,我们可以获得该数字的所有除数:--

import numpy
ls = [2,2,3,4]

x = numpy.prod(ls)

from sympy import divisors
divisors_x = divisors(x)

给你!!这是列表(divisors_x)

答案 3 :(得分:-1)

您可以将其分解为三个步骤:

  • 获取数字列表的所有排列
  • 对于每个排列,创建所有可能的分区
  • 对于分区中的每个子列表,计算产品

对于排列,您可以使用itertools.permutations,但据我所知,分区没有内置函数,但写入(或查找)并不困难:

def partitions(lst):
    if lst:
        for i in range(1, len(lst) + 1):
            for p in partitions(lst[i:]):
                yield [lst[:i]] + p
    else:
        yield []

对于(1,2,3,4)这样的列表,这会生成[(1),(2),(3),(4)][(1),(2),(3,4)][(1),(2,3),(4)][(1),(2,3,4)]等,但不是,例如[(1,3),(2),(4)];这就是我们为什么还需要排列的原因。但是,对于所有排列,这将创建许多有效重复的分区,例如[(1,2),(3,4)][(4,3),(1,2)](对于data为182),但除非您的列表特别长,否则应该不是太大的问题。

我们可以结合第二步和第三步;通过这种方式,我们可以在出现所有副本时立即清除它们:

data = (2, 2, 3, 4)
res = {tuple(sorted(reduce(operator.mul, lst) for lst in partition))
       for permutation in itertools.permutations(data)
       for partition in partitions(permutation)}

之后,res{(6, 8), (2, 4, 6), (2, 2, 3, 4), (2, 2, 12), (48,), (3, 4, 4), (4, 12), (3, 16), (2, 24), (2, 3, 8)}

或者,您可以将它组合在一个稍微复杂的算法中。由于数据集中有两个2,这仍会生成一些重复项,可以通过在集合中进行排序和收集来再次删除。结果与上述相同。

def all_partitions(lst):
    if lst:
        x = lst[0]
        for partition in all_partitions(lst[1:]):
            # x can either be a partition itself...
            yield [x] + partition
            # ... or part of any of the other partitions
            for i, _ in enumerate(partition):
                partition[i] *= x
                yield partition
                partition[i] //= x
    else:
        yield []

res = set(tuple(sorted(x)) for x in all_partitions(list(data)))