繁体   English   中英

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

[英]Find all the combinations from the given set of numbers that apply to some rules

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

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

my_list = [400, 200, 100, 50, 25]
my_dict = {400: 8, 200:4, 100: 2, 50: 2, 25: 2}

我需要找到可以从 my_list 中的数字构建的所有可能组合,当它们应该应用以下规则时:

  1. 组合中可能存在相同的数字( [400, 400, 400]是有效组合)
  2. 顺序无关紧要( [400, 200, 100] [100, 200, 400]对我来说与[100, 200, 400]相同)
  3. 组合中的数字总和不应超过1200
  4. my_dict[my_list_item]的总和不应超过 24(例如[400, 400, 400, 100]无效,因为my_dict[400]+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)

假设你想“名单每个重复组合”列表中,我写了一个代码,它计算。

它使用一个 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,您将不需要递归解决方案。 combine_with_replacement 迭代器将为您提供组合,您只需要检查您的条件。 根据您的要求,您将需要一组强大的组合(即所有尺寸的组合):

例如:

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)

如果您打算以某种方式处理组合,您可以将它放在一个函数中并使用yield combo而不是print(combo)

输出:

(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)

请注意,这是一种非优化的蛮力方法,对于小数据集可能没问题,但随着您拥有更多数据,将花费指数级的时间。 有更高级的方法(使用递归)可以通过检查部分总和和/或使用 meoization 来跳过整个组合。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM