Python 从给定的一组数字中找出适用于某些规则的所有组合

Python 从给定的一组数字中找出适用于某些规则的所有组合,python,algorithm,statistics,Python,Algorithm,Statistics,我非常感谢您对以下问题的帮助: 我有一个数字列表和一本字典: my_list = [400, 200, 100, 50, 25] my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2} 我需要从我的_列表中的数字中找到所有可能的组合,它们应该应用以下规则: 组合中可能有相同的数字([400400400]是有效的组合) 顺序无关紧要([400200100]对我来说与[100200400]相同) 组合中的数字总和不得超过1200 my_dict[my_lis

我非常感谢您对以下问题的帮助:

我有一个数字列表和一本字典:

my_list = [400, 200, 100, 50, 25]
my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2}
我需要从我的_列表中的数字中找到所有可能的组合,它们应该应用以下规则:

  • 组合中可能有相同的数字(
    [400400400]
    是有效的组合)
  • 顺序无关紧要(
    [400200100]
    对我来说与
    [100200400]
    相同)
  • 组合中的数字总和不得超过1200
  • my_dict[my_list_item]
    的总和不应超过24(例如
    [400400400100]
    无效,因为
    my_dict[400]+my_dict[400]+my_dict[100]=8+8+8+2=26,因此它不是有效的组合)
  • 任何关于python算法的想法都可以解决这个问题。
    谢谢

    以下是使用迭代器递归执行此操作的代码,以避免在内存中保存太多内容

    #! /usr/bin/env python3
    
    def combs (numbers, value_of, max_numbers=1200, max_value=24, min_i=0):
        if len(numbers) <= min_i:
            yield []
        else:
            for comb in combs(numbers, value_of, max_numbers, max_value, min_i+1):
                yield comb
                comb_copy = [n for n in comb] # Copy to avoid sharing bugs.
                numbers_sum = sum(comb)
                values_sum = sum([value_of[i] for i in comb])
                while True:
                    comb_copy.append(numbers[min_i])
                    numbers_sum += numbers[min_i]
                    if max_numbers < numbers_sum:
                        break
                    values_sum += value_of[numbers[min_i]]
                    if max_value < values_sum:
                        break
                    yield comb_copy
    
    
    my_list = [400, 200, 100, 50, 25]
    my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2}
    
    for c in combs(my_list, my_dict):
        print(c)
    
    #/usr/bin/env蟒蛇3
    def梳(数量、值、最大值=1200、最大值=24、最小值=0):
    
    如果len(numbers)假设您想要“列表的每个组合都有重复”,我编写了一个代码来计算它

    它使用while循环,每次递增组合长度计数器。 由于组合的长度可以无限增长,因此该指示器用于停止循环,当未找到单个组合时,循环将激活

    from itertools import combinations_with_replacement
    
    my_list = [400, 200, 100, 50, 25]
    my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2}
    
    final_list = []
    
    combinationLength = 1
    while True:
        c = list(combinations_with_replacement(my_list, combinationLength)) #generate every combination of length combinationLength
        countNextCombination = False #indicator to break the while loop
    
        for combination in c: 
            if (sum(combination) <= 1200):
                dicsum=0
                for j in combination:
                    dicsum+=my_dict[j]
                if (dicsum<=24):
                    final_list.append(list(combination))
                    countNextCombination = True
    
        if countNextCombination == False: #if not a single combination was valid, finish the loop
            break
        combinationLength += 1
    
    print (final_list)
    
    从itertools导入组合并替换
    我的清单=[4002001005025]
    我的圣经={400:8200:4100:2,50:2,25:2}
    最终清单=[]
    组合长度=1
    尽管如此:
    c=列表(带替换的组合(my_列表,combinationLength))#生成每个长度组合combinationLength
    countNextCombination=False#用于中断while循环的指示器
    对于c中的组合:
    
    如果使用itertools(sum(composition),则不需要递归解决方案。带有替换迭代器的组合将为您提供组合,您只需检查您的条件。根据您的要求,您将需要组合的幂集(即所有大小的组合):

    例如:

    from itertools import combinations_with_replacement as combine
    
    my_list = [400, 200, 100, 50, 25]
    my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2}
    
    for size in range(2,len(my_list)+1):
        for combo in combine(my_list, size):
            if sum(combo) <= 1200 \
            and sum(my_dict[c] for c in combo) <= 24:
                print(combo)
    

    请注意,这是一种非优化的蛮力方法,可能适用于小数据集,但随着数据量的增加,这将花费指数级的时间通过检查部分和和和/或使用meoization,这将跳过整个组合样本。

    您将如何手动完成?此外,这一部分还不太清楚-输出“组合”可能需要多长时间?很棒的代码:)但在遇到此类问题时,使用递归好吗。。。?我有一种感觉,直接计算组合将减少由所有递归引起的不必要的计算(即,有许多相同组合的重复)@KentaNomoto如果你被要求计算计数,像这样的递归非常可怕,因为输出可能非常大。但在这里,我们被要求实际找到这些组合。递归没有很多好的替代方法——你能做的最好的方法就是限制在产生大量输出时使用的内存量。哦,我现在明白了。对在这里,递归可能是最有效的方法。正如你所说的,与其他方法相比,从一个非常大的输入中使用的内存要少得多。@KentaNomoto注意,诀窍不仅仅是递归。它是递归和迭代器。这样,您只需保留在内存中生成组合的位置,而不是整个数据结构。仅仅递归地生成完整的数据集是行不通的,问题是“找到组合”,而不是“找到多少组合”。因此,你在回答一个不同的问题。@B你到底是什么意思?“final_list”变量是所有组合的列表。编辑:哦,我现在明白了,combinationLength变量的命名可能有点误导。它不是总组合的长度,而是保存组合长度的变量(例如[200100100]是组合长度为3)正确。我的错。在这种情况下,您可能最终在内存中保留的内存量非常大,以至于您的代码根本无法运行。
    (400, 400)
    (400, 200)
    (400, 100)
    (400, 50)
    (400, 25)
    ...
    (50, 50, 50, 50, 50)
    (50, 50, 50, 50, 25)
    (50, 50, 50, 25, 25)
    (50, 50, 25, 25, 25)
    (50, 25, 25, 25, 25)
    (25, 25, 25, 25, 25)