I aim to write a function that splits a budget across options by comparing options based on their benefit/cost ratio and stores them in a list of nested dicts. When multiple options with the same benefit/cost ratio are available, each option shall be pursued separately (as downstream element which in turn may have multiple downstream elements) and reflected as a list of dicts for its upstream dict. There is no limitation as to how many options may occur.
def get_all_allocation_proposals(budget, options, upstream_element=dict()):
# accepts:
# budget to be allocated
# list of options
# returns:
# a list of allocation proposals
# filter options for affordable options and sort by cost benefit ratio
options = [x for x in options if x['cost'] <= budget]
options = sorted(options, key=lambda x: (
x['benefit_cost_ratio'], x['benefit']), reverse=True)
if (len(options) > 0):
# select the best options
best_bc_ratio = options[0]['benefit_cost_ratio']
best_options = [
x for x in options if x['benefit_cost_ratio'] == best_bc_ratio]
upstream_element['downstream_elements'] = []
for current_element in best_options:
downstream_options = remove_conflicting_options(
current_element, options)
downstream_budget = budget - current_element['cost']
current_element['donstream_budget'] = downstream_budget
downstream_elements = get_all_allocation_proposals(downstream_budget,
downstream_options,
current_element)
if downstream_elements is not None:
current_element['downstream_elements'] = downstream_elements
upstream_element['downstream_elements'].append(current_element)
return upstream_element
else:
return None
In the code above, when the elements are appended, self referencing dict values are created. Why is that the case and how can I avoid that? All I want to do is to pass on all downstream elements to the first call stack. Is there something fundamentally flawed with my recursion pattern?