我觉得有一个优雅的 Python 解决方案可以解决我一直在尝试用 VBA 解决的这个问题。有人可以帮忙吗?
如何生成满足以下条件的数字列表:
- 都是整数吗
- 总数首先在类型之间进行拆分。
- 这些数字进一步分为子类型并进行优化以满足所需的百分比。
- 总和不超过指定的 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))