from decimal import Decimal
"""
需求:多个订单认款多笔流水
第一步:找出每一笔流水中每个可能的组合
第二步:循环所有的可能的组合,用字典相加和目标匹配,保证不重复覆盖所有的订单和所有的流水
第三步:最后输出所有的可能组合直接把所有的流水和订单匹配完成
"""
# 递归函数,返回 arr 中找出 sum 值为 target 的组合及它们的索引
def find_combinations(arr, target):
# 如果 target 是单个值,则将其转化为单元素列表
if isinstance(target, (int, float)):
target = [Decimal(str(target))]
# 递归函数,返回 arr 中找出 sum 值为 target 的组合及它们的索引
i = 0
def helper(arr, index, target, res, path):
if target == 0:
# 创建一个新的字典,其中键是索引,值是元素值
comb_dict = {i: arr[i] for i in path}
res.append(comb_dict)
return
if target < 0 or index >= len(arr):
return
num = arr[index]
if isinstance(num, (int, float)):
num = Decimal(str(num))
# 递归调用,包含当前元素
helper(arr, index + 1, target - num, res, path + [index])
# 递归调用,不包含当前元素
helper(arr, index + 1, target, res, path)
result = {}
for t in target:
res = []
helper(arr, 0, Decimal(str(t)), res, [])
# 将结果存储到字典中,键是目标值,值是组合的字典列表
i += 1
result[str(float(t)) + '-' + str(i)] = res
return result
# 获取到所有可能的组合之后,再次获取组合结果中最后能包含arr所有的值和target中的所有的值
def find_combinations_with_sources(lists, target_dict):
def backtrack(index, current_combination, path, result):
if index == len(lists):
if current_combination == target_dict:
# 构建包含来源信息的最终结果
final_combination = {
k: (v, f"list{d[0]}")
for d in path
for k, v in d[1].items()
}
result.append(final_combination)
return
for i, dict_item in enumerate(lists[index]):
new_path = path + [(index + 1, dict_item)] # 确保列表索引从1开始
new_combination = current_combination.copy()
if not set(dict_item.keys()) & set(current_combination.keys()):
new_combination.update(dict_item)
backtrack(index + 1, new_combination, new_path, result)
result = []
backtrack(0, {}, [], result)
return result
arr = [42.9, 257.6, 550, 1200, 2302, 2302, 88.8, 6182.8, 480, 147, 2220, 798, 237.8, 40805, 45654.4, 282, 9982.5, 448,
788, 3097, 9472, 200, 970, 327]
target = [37950.6, 90884.2]
res = find_combinations(arr, target)
print("res===============", res)
listall = []
for value in res.values():
listall.append(value)
print("listall=================", listall)
# for k in sorted(res.keys()):
# print("{}: {}".format(k, res[k]))
target_dict = {index: value for index, value in enumerate(arr)}
# 调用函数并打印结果
combinations = find_combinations_with_sources(listall, target_dict)
for combination in combinations:
source_info = combination.values()
group_by_list = {}
for value, source in source_info:
if source not in group_by_list:
group_by_list[source] = []
group_by_list[source].append(value)
for source, values in group_by_list.items():
print(f"{source}: {values}")
print("\n---\n")
注:用了两次回溯算法,大家有好的方法请帮忙指正,目前的方法也会有些固有的缺陷