【问题标题】:How do I generate a list of all possible combinations from a single element in a pair, from numerous pairs nested within a parent list?如何从一对中的单个元素,从嵌套在父列表中的众多对中生成所有可能组合的列表?
【发布时间】:2021-02-05 01:46:30
【问题描述】:

我发现自己处于一种独特的情况,我需要将列出的一对数字中的单个元素相乘,其中每对都嵌套在一个父元素列表中。例如,我的预定义变量为:

output = []
initial_list = [[1,2],[3,4],[5,6]]

我正在尝试计算一个输出,使得每个元素都是每对中单个元素的唯一组合(总是长度为len(initial_list))的乘积。使用我的initial_list 示例,我希望生成一个长度为pow(2 * len(initial_list)) 的输出,该输出对于initial_list 中的任何“n”对(最少2 对)都是可伸缩的。所以在这种情况下,输出的每个元素如下:

output[0] = 1 * 3 * 5
output[1] = 1 * 3 * 6
output[2] = 1 * 4 * 5
output[3] = 1 * 4 * 6
output[4] = 2 * 3 * 5
output[5] = 2 * 3 * 6
output[6] = 2 * 4 * 5
output[7] = 2 * 4 * 6

在我的具体情况下,除了output[0] 之外,输出分配的顺序无关紧要,我需要等效于initial_list 中每对中第一个元素的乘积。继续生成输出列表以使每个元素都是每个列表中每个元素的唯一组合的最佳方法是什么?

...

我最初的方法是使用;

from itertools import combinations 
from itertools import permutations
from itertools import product

以某种方式生成每个可能组合的列表,然后将产品相乘并将每个产品附加到输出列表中,但我无法等待成功实施这些工具。从那以后,我尝试创建一个递归函数,将for x in range(2): 与嵌套递归调用相结合,但我又一次找不到解决方案。

请比我更有经验和聪明的人帮助我;任何和所有的帮助表示赞赏!谢谢!

【问题讨论】:

  • initial_list 是否总是在列表中包含列表?
  • 正确。 initial_list 变量将始终包含不同长度的列表中的列表对。

标签: python python-3.x list recursion nested-lists


【解决方案1】:

这个问题也可以用动态规划来解决

output = [1, ]
for arr in initial_list:
    output = [a * b for a in arr for b in product]

如果你只有一个子数组,这个问题很容易解决——输出是给定的子数组。

假设您解决了第一个n - 1 子数组的问题,并得到了输出。新的子数组被附加。输出应该如何改变?新输出是前一个输出和“新”子数组的所有成对乘积。

【讨论】:

    【解决方案2】:

    仔细看,有一个简单的模式。假设有 n 个子列表,每个子列表有 2 个元素:在索引 0 和 1 处。现在,所选索引可以表示为长度为 n 的二进制字符串。
    它将以0000..000 开头,然后是0000...0010000...010 等等。所以你需要做的就是:

    n = len(lst)
    for i in range(2**n):
        binary = bin(i)[2:] #get binary representation
        for j in range(n):
            if binary[j]=="1":
                #include jth list's 1st index in product
            else:
                #include jth list's 0th index in product
    

    问题将是一个可扩展的解决方案,因为您正在生成所有可能的对,时间复杂度将为 O(2^N)

    【讨论】:

      【解决方案3】:

      您使用itertools.product 的想法很棒!

      import itertools
      initial_list = [[1,2],[3,4],[5,6]]
      combinations = list(itertools.product(*initial_list))
      # [(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
      

      现在,您可以使用for-loops 或functools.reduce 获取combination 中每个元组的乘积,也可以使用python 3.8 中引入的math.prod

      import itertools
      import math
      initial_list = [[1,2],[3,4],[5,6]]
      output = [math.prod(c) for c in itertools.product(*initial_list)]
      # [15, 18, 20, 24, 30, 36, 40, 48]
      
      import itertools
      import functools
      import operator
      initial_list = [[1,2],[3,4],[5,6]]
      output = [functools.reduce(operator.mul, c) for c in itertools.product(*initial_list)]
      # [15, 18, 20, 24, 30, 36, 40, 48]
      
      import itertools
      output = []
      for c in itertools.product(*initial_list):
        p = 1
        for x in c:
          p *= x
        output.append(p)
      # output == [15, 18, 20, 24, 30, 36, 40, 48]
      

      注意:如果您更熟悉 lambda,operator.mul 几乎等同于 lambda x,y: x*y

      【讨论】:

        【解决方案4】:

        itertools.productmath.prod 很合适 -

        from itertools import product
        from math import prod
        
        input = [[1,2],[3,4],[5,6]]
        output = [prod(x) for x in product(*input)]
        print(output)
        
        [15, 18, 20, 24, 30, 36, 40, 48]
        

        【讨论】:

          【解决方案5】:

          不使用任何外部库

          def multi_comb(my_list):
              """
                  This returns the multiplication of 
                  every possible combinationation of
                  the `my_list` of type [[a1, a2], [b1, b2], ...]
          
                  Arg: List
                  Return: List
              """
              if not my_list: return [1]
          
              a, b = my_list.pop(0)
              result = multi_comb(my_list)
          
              left = [a * i for i in result]
              right = [b * i for i in result]
          
              return (left + right)
              
          print(multi_comb([[1, 2], [3, 4], [5, 6]]))
          
          # Output
          # [15, 18, 20, 24, 30, 36, 40, 48]
          

          我正在使用递归来获得结果。这是其工作原理的直观说明。

          我们可以采用自下而上的方法来更好地了解该程序的工作原理,而不是采用自上而下的方法。

          1. 在最后一步,ab 分别变为 56。使用空列表调用 multi_comb() 会返回 [1] 作为结果。所以leftright 变成[5][6]。因此我们将[5, 6] 返回到上一步。

          2. 在最后第二步,ab 分别是 34。结果从最后一步我们得到了[5, 6]。将结果中的每个值与ab 相乘(注意leftright)后,我们将结果[15, 18, 20, 24] 返回到上一步。

          3. 在我们的第一步,即我们的开始步骤,我们将ab 分别作为12。我们最后一步返回的值成为我们的结果,即[15, 18, 20, 24]。现在我们将ab 与这个结果相乘,并返回我们的最终输出。

          注意:
          该程序仅在列表的形式为 [ [a1, a2], [b1, b2], [c1, c2], ... ] 时才有效,正如 cmets 中的 OP 所告知的那样。解决包含n项目子列表的列表的问题在代码中会略有不同,但概念与此答案相同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-04-02
            • 2013-04-14
            • 2017-08-13
            • 2021-03-14
            • 2012-05-13
            • 1970-01-01
            相关资源
            最近更新 更多