【问题标题】:How to generate and filter efficiently all combinations of a list of list product如何有效地生成和过滤列表产品列表的所有组合
【发布时间】:2019-08-19 02:05:36
【问题描述】:

大家好,这是问题所在。我在输入 [[1,2,3],[4,5,6],[7,8,9]]...等中有这样的东西

我想生成这些列表的所有可能的产品组合,然后将结果组合的每个元素相乘,最终在一个区间内过滤结果。

所以先输入一个n列表[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]...等

然后会给出 (1,4,7,10) (1,4,7,11) (1,4,7,12) 等等

然后将 n 中 k 的结果组合起来,例如第一行的 (1,4,7)(1,4,10)(1,7,10)

x 的乘积为 1*4*7 = 28, 1*4*10 = 40, 1*7*10 = 70

从中只得到唯一组合和预先选择的区间内需要的结果:如果 x > 50 和 x

我试过

    def mult(lst):                 #A function mult i'm using later
        r = 1
        for element in lst:
           r *= element
        return round(r)

    s = []                                #Where i add my list of list
    for i in range(int(input1)):
        b = input("This is line %s : " % (i+1)).split()
        for i in range(len(b)):
           b[i] = float(b[i]) 
        s.append(b)

    low_result = input("Expected low_result : ")
    high_result = input("Expected high_result : ")

    combine = []
    my_list = []

    for element in itertools.product(*s):
       l= [float(x) for x in element]
       comb = itertools.combinations([*l], int(input2))
       for i in list(comb):
          combine.append(i)
          res = mult(i)
          if res >= int(low_result) and res <= int(high_result):
             my_list.append(res) 
             f = open("list_result.txt","a+")
             f.write("%s : result is  %s\n" % (i, res))
             f.close()

它总是导致内存错误,因为我正在寻找的变化太多。

我想要的是一种从包含 20 个或更多元素的列表中生成所有产品的方法,并为我需要的结果(间隔)生成 n 中的 k 组合。

【问题讨论】:

  • 如果您正在寻找 AXBXCX... 然后尝试获取一个子集 dim = n-1 ,不妨从选择 (n-1) 个空格开始?还是我错过了什么?
  • 尝试用生成器替换列表,将 [] 替换为 () 他们会节省一些内存
  • 如果 l 是一个列表,[*l] 也与 l 相同
  • 我认为 numpy 会帮助你提高一些性能。但我不是 Python 数字人
  • 如果我将 [] 替换为 () 它不会与组合有关,因为它会给它太多的参数不?

标签: python python-3.x


【解决方案1】:

正如上面所建议的,我认为这可以通过在任何时候都不在内存中保存数组来完成,而不会爆炸你的内存。但主要问题是运行时。

数学

我们是这样写的:

  • 产生mn项目n ** m的每个组合
  • 然后从mC(m, c) 中选择c 项目

这是非常大的。如果我们有m=25 行,每个n=3 项并在其中选择c=3 项,我们得到:

如果我们:

  • m 行中选择c 行:C(m, c) 和以前一样
  • 然后从这些c 行中选择n 项目的每个组合:n ** c

使用m=25 行,每个n=3 项,然后在其中选择c=3 项,我们得到:

  • = n ** c * C(m, c)
  • = 3 ** 3 * 2300
  • = 20700

现在这是一个可以解决的问题。

代码

from itertools import product, combinations


def mult(values, min_value, max_value):
    """
    Multiply together the values, but return None if we get too big or too
    small
    """
    output = 1

    for value in values:
        output *= value

        # Early return if we go too big
        if output > max_value:
            return None

        # Early return if we goto zero (from which we never return)
        if output == 0 and min_value != 0:
            return None

    if output < min_value:
        return None

    return output


def yield_valid_combos(values, choose, min_value, max_value):
    # No doubt an even fancier list compression would get this too
    for rows in combinations(values, choose):
        for combos in product(*rows):
            value = mult(combos, min_value, max_value)

            if value is not None:
                yield combos, value


values = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]


with open('list_result.txt', 'w') as fh:
    for selection, value in yield_valid_combos(
            values, choose=3, min_value=50, max_value=100):
        fh.write('{}: result is {}\n'.format(selection, value))

此解决方案也不会返回重复的答案(除非相同的值出现在多行中)。

作为一种优化,如果我们检测到结果太大或太小,乘法方法会尝试提前返回。我们也只打开文件一次,然后不断向其中添加行。

进一步优化

您还可以通过筛选出对解决方案没有帮助的值来提前优化您的值集。但是对于较小的 c 值,您可能会发现这甚至没有必要。

值的最小可能组合是每行中最小值集合中的c 个项目。如果我们从最小值集合中取出c - 1 最小的项目,将它们相乘,然后将最大值除以这个数字,它为我们提供了一个可以在解决方案中的最大值的上限。然后我们可以筛选掉所有高于这个值的值(减少排列)

【讨论】:

  • 遗憾的是,这些值不像 [[1.16,6.3,12],[1.27,5.5,9],[2.42,3.3,2.85],[1.3,5.4,9.5] ,[2.78,3.35,2.32],[2.45,2,1.88]] 最多可能有 25 个元素或更多。这就是为什么我真的很好奇您在回答结尾处呈现的方式,因为处理所有这些组合的时间需要看起来几乎无限否?
  • 可以将上述逻辑概括为任意值。如果我们从每个集合中收集最小值的集合,我们可以通过以下方式为可以作为解决方案一部分的最大值创建一个上限:从该集合中删除最大值,将其余值相乘,将最大值除以那个值。然后我们可以从高于该值的集合中删除值。这将加快这个过程,因为它减少了排列,但如果我们发现任何特定的集合是空的,我们也知道在开始之前没有解决方案。
  • 啊……抱歉,实际上是从最小值集中取choose - 1 最小值,然后除以最大值。
  • 我想我已经破解了,产品和选择应该是相反的......我会更新答案。
猜你喜欢
  • 2017-11-27
  • 1970-01-01
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 2023-03-15
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多