【问题标题】:Determine list of all possible products from a list of integers in Python从 Python 中的整数列表中确定所有可能产品的列表
【发布时间】:2016-09-10 16:27:38
【问题描述】:

在 Python 2.7 中,我需要一个返回 list or tuple of int 的所有可能产品的方法。 IE。如果输入是(2, 2, 3, 4),那么我想要一个类似的输出

  • (3, 4, 4), 2 * 2 = 4
  • (2, 4, 6), 2 * 3 = 6
  • (2, 3, 8), 2 * 4 = 8
  • (3, 4, 4), 2 * 2 = 4
  • (2, 2, 12), 3 * 4 = 12
  • (2, 24), 2 * 3 * 4 = 24
  • (3, 16), 2 * 2 * 4 = 16
  • (4, 12), 2 * 2 * 3 = 12
  • (48), 2 * 2 * 3 * 4 = 48

包含在list or tuple 中。我认为使用itertools 中的combinations 可能会实现一个不错的实现,但我将不胜感激。请注意,我只对不同的列表感兴趣,int 的顺序不起作用。

编辑

为了澄清一些进一步的解释。取第一个输出列表。输入是(2, 2, 3, 4)(总是)。然后我从列表中取出 2 和 2 out 并将它们相乘,所以现在我得到了一个列表 (3, 4, 4)。 3 和 4 来自输入,最后 4 来自产品。

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

【问题讨论】:

  • 您能展示一下您的尝试吗?谢谢。
  • @Mr.goosberry 我还没有尝试过任何事情,因为我无法绕着那种循环转头。我注意到这个问题我得到了很多减分。我做错了什么?
  • 您的输出不清楚。例如,为什么元组(3, 4, 4) 在产品2 * 2 = 4 之前?此外,您可能因为没有展示自己的任何代码而投了反对票,您提供了毫无意义的期望输出,而且通常您展示的自己的工作很少。你可以编辑你的问题来解决这些问题,你可能很快就会得到支持和一些好的答案。我鼓励你做这样的编辑。
  • @mr.bjerre 是的。如果您根本找不到解决方法,请确保您的输出定义明确,并为您的问题提供清晰易懂的示例。
  • @RoryDaulton 输入为(2, 2, 3, 4)。然后我从列表中取出 2 和 2 out 并将它们相乘,所以现在我得到了一个列表 (3, 4, 4)。 3 和 4 来自输入,最后 4 来自产品。有意义吗?

标签: python algorithm combinations combinatorics


【解决方案1】:

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

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

查找子集是一个众所周知的问题,因此我相信您可以找到有关如何做到这一点的资源。请记住,具有 N 个元素的集合有 2**N 个 setbset。

【讨论】:

  • 非常精确。我将尝试在此基础上提出自己的算法。虽然现在; tobias_k 的代码就足够了。如果我有必要的分数,我会为你提供答案。
【解决方案2】:

假设您有一个由 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) 和二进制 (bin) 并返回乘法的值。

【讨论】:

  • 这没有任何意义。这如何解决 OP 的问题?
  • 感谢您的努力 - 它确实为我解决了这个问题。如果我有必要的分数,我会为你提供答案。
【解决方案3】:

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

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

x = numpy.prod(ls)

from sympy import divisors
divisors_x = divisors(x)

给你!!这是列表(divisors_x)

【讨论】:

    【解决方案4】:

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

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

    对于排列,您可以使用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)))
    

    【讨论】:

    • 排列一个集合没有多大意义,一个集合的所有“排列”都有相同的分区。分区也不是解决这个问题的正确方法,通过分区,你过度解决了这个问题,然后你通过对事物进行分类并将所有东西放入一个集合中来将它扫到地毯下。
    • @BiRico 我不是在创建一个集合而是一个列表(实际上是一个元组)的排列,并且排列是必要的,因为(2,2,3,4) 的分区与(2,3,2,4) 不同。
    • @BiRico 阅读我发布的代码。 ;-) 是的,链接指向集合的分区,但是算法正在创建列表的分区(它们不同并且取决于顺序),尤其是因为它更简单。此外,真正的集合分区算法将不起作用,因为输入不是集合(其中有两个数字 2)
    • 我不知道你为什么要在这件事上与我作对:) 我想教你一些东西。您的代码为一个应该有 11 个结果的问题生成了 192 个结果……有些不对劲。
    • @BiRico 我非常清楚这一点,并指出存在重复项,这些重复项将通过排序和收集它们来过滤掉。但除非 OP 告诉我们他的名单特别长,否则我认为这不是问题。
    猜你喜欢
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2011-02-20
    • 1970-01-01
    相关资源
    最近更新 更多