0

我觉得有一个优雅的 Python 解决方案可以解决我一直在尝试用 VBA 解决的这个问题。有人可以帮忙吗?

如何生成满足以下条件的数字列表:

  1. 都是整数吗
  2. 总数首先在类型之间进行拆分。
  3. 这些数字进一步分为子类型并进行优化以满足所需的百分比。
  4. 总和不超过指定的 Total。

这个问题的例子:

  • 您计划建造最多 102 个住宅单元。
  • 建筑类型:其中 40% 将是工作室,60% 将是联排别墅建筑类型。(可以有更多或更少的类型)
  • 公寓的未来居住者有两个优先级列表:辅助和无辅助
    • 需要完全满足辅助(A)列表中的单元分配百分比,并且非辅助(U)列表是灵活的。如果可能,我们希望非辅助 (U) 列表最多占总单位的 20%,但我们绝对需要至少 80% 的总单位是辅助(A) 单位。
  • Assisted(A) 单位总数为 102x80% = 81.6 个单位(已经不是整数)
    • 至少 10% 的辅助 (A) 列表单元必须针对老年人。
    • 至少 40% 的辅助 (A) 列表单元必须用于家庭。
    • 其余 50% 的辅助 (A) 列表单元面向有抱负的数据科学家。

其余 20% 的总单位是无人协助 (U) 入住单位。

所以:

  • 总计:102 个单位。
  • Construction_type_categories=[.4, .6](102 个单位分为工作室和联排别墅:40% 和 60%)
  • Assisted=[.1,.4,.5](80% 以上的总单位是辅助型,根据列表中的百分比进一步分类为老年人、家庭、其他入住)
  • 无协助单位是不属于协助名单 80% 以上的剩余单位。(最多占总单位的 20%)

结果:

[4,16,12,8,7,25,19,11]

分解:

  • 4个工作室单位协助长者
  • 为家庭提供 16 个工作室单位
  • 12 个工作室单元,用于其他辅助入住类型
  • 8 个工作室单元(无辅助)
  • 7个联排别墅单位协助长者
  • 为家庭提供 25 套联排别墅
  • 19 套其他辅助入住类型的联排别墅单位
  • 11 个联排别墅单元(独立)。

我想首先生成一个初步的四舍五入数组,然后循环并进行调整。它看起来很乏味,我开始考虑使用 numpy 生成一个大的数字矩阵并按概述的标准进行过滤。

手动生成和优化数字非常耗时,因此我感谢任何有关更好解决方案的帮助。

import math

def is_even(x):
    if x % 2 == 0:
        return True
    else:
        return False

total=102 
unassisted=.2
unassisted_unit_count= math.floor(total*unassisted)
assisted_unit_count=total- unassisted_unit_count

construction_type_categories=[.4, .6] #Must be even.
assisted_subcategories=[.1,.4,.5] #Last element here will be of least priority.


def Unit_Number_Getter(L):

    if L[1]=='total_constr_type_amounts':
        giventotal= total
    if L[1]=='assisted_constr_type_amounts':
        giventotal= assisted_unit_count

    #Spliting by construction type (preliminary).
    constr_type_amounts=[]
    for ct in construction_type_categories:
        constr_type_amounts.append(round(giventotal * ct))

    #Making the unit counts even for the total construction type amounts (need to).
    for p in constr_type_amounts:
        if not is_even(p):
            add_here=constr_type_amounts.index(p)
            for f in constr_type_amounts:
                if not is_even(f):
                    from_here= constr_type_amounts.index(f)
            constr_type_amounts[add_here] +=1
            constr_type_amounts[from_here] -=1
    assert sum(constr_type_amounts)==giventotal

    print L[1]
    print(constr_type_amounts)
    L[0]=constr_type_amounts


total_constr_type_amounts=0
assisted_constr_type_amounts=0

List_of_lists=[[total_constr_type_amounts,"total_constr_type_amounts"],[assisted_constr_type_amounts,"assisted_constr_type_amounts"]]

#Established the unit counts for each construction type (for Assisted and total units)
for L in List_of_lists:
    Unit_Number_Getter(L)


#Getting a list of the unit counts for each assisted subcategory in each constr type.
testlist=[]
for c in List_of_lists[1][0]:
    already_added=0
    for a in assisted_subcategories[:-1]:
        adding_now= math.ceil(c * a)
        testlist.append(adding_now)
        already_added+=adding_now
    #^Added the priority assisted units (all but the last element).   

    #Now will add the last of the assisted units.
    testlist.append(c-already_added)

    #Now will add he least prioritized unassisted units up to the max.
    Max_unassisted_units= List_of_lists[0][0][List_of_lists[1][0].index(c)]-c

    testlist.append(Max_unassisted_units)

    assert ((c+Max_unassisted_units)== List_of_lists[0][0][List_of_lists[1][0].index(c)])#all units present

print("Result: "+ "\n" + str(testlist))     
4

0 回答 0