我认为解决此问题的最简单方法是使用itertools.combinations。
要使用它,您首先需要将 dict 的硬币数量转换为 list 的硬币数量:
coins = {2: 0, 1: 0, 0.5: 0, 0.2: 0, 0.1: 0, 0.05: 1, 0.02: 4, 0.01: 3}
# stores a list of all coin values, ie [0.2, 0.2, 1] if one has two 20c and 1 $1
coin_list = []
for value, count in coins.items():
if count > 0:
coin_list += [value] * count
然后,可以使用itertools.combinations 获取每种可能组合大小的每种可能组合,将其相加,并将 if 保存到输出 dict。
由于您想为每个值存储所有可能的硬币组合,您可以将dict 中的每个项目转换为set 的collections.Counter。 set 只会存储唯一的硬币数量:
import itertools
import collections
output_dict = dict()
for comb_size in range(len(coin_list)):
# gets every combination of every size from coin_list
for combination in itertools.combinations(coin_list, comb_size):
# sums up all coins in combination
value = sum(combination)
# get the set of existing coins for value/create if it doesn't exist
value_set = output_dict.get(value, set())
# collections.Counter counts up each coin in a combination
counter = collections.Counter(combination)
# we need to convert counter to a hashable form to add it to a set()
value_set.add(tuple(sorted(counter.items())))
output_dict[value] = value_set
最后,因为将浮点数相加会导致奇怪的结果(如0.1 + 0.2 = 0.300000001),打印时您可以将总和的值四舍五入到最接近的分(并使用模块pprint 使格式更好):
import pprint
pprint.pprint({round(x, 2): y for x,y in output_dict.items()})
这将为每个硬币价值总和打印出set 的dict。每个set 包含tuples 对(硬币价值,硬币数量),即对于 3 美分,一个可以有 3 * 1c 硬币 (((0.01, 3),)),或 1c + 2c (((0.01, 1), (0.02, 1))):
{0: {()},
0.01: {((0.01, 1),)},
0.02: {((0.02, 1),), ((0.01, 2),)},
0.03: {((0.01, 3),), ((0.01, 1), (0.02, 1))},
0.04: {((0.02, 2),), ((0.01, 2), (0.02, 1))},
0.05: {((0.01, 1), (0.02, 2)), ((0.05, 1),), ((0.01, 3), (0.02, 1))},
0.06: {((0.02, 3),)},
0.07: {((0.01, 1), (0.02, 3))},
0.08: {((0.01, 2), (0.02, 3))},
0.09: {((0.01, 3), (0.02, 3))},
0.1: {((0.01, 3), (0.02, 1), (0.05, 1)), ((0.01, 2), (0.02, 4))},
0.11: {((0.01, 3), (0.02, 4))},
0.12: {((0.01, 3), (0.02, 2), (0.05, 1))},
0.13: {((0.01, 2), (0.02, 3), (0.05, 1)), ((0.02, 4), (0.05, 1))},
0.14: {((0.01, 1), (0.02, 4), (0.05, 1)), ((0.01, 3), (0.02, 3), (0.05, 1))},
0.15: {((0.01, 2), (0.02, 4), (0.05, 1))}}