0
def find_the_best_solution(shipping_request, list, current_solution, best_shipping_solution):
    if shipping_request == {}:
        return current_solution

    for item in shipping_request:
        for i in range(0,len(list), 1):
            length_of_combination = i+1
            combinations = itertools.combinations(list, length_of_combination)
            for x in combinations:
                if sum(x) >= shipping_request[item]:
                    if sum(x) > shipping_request[item]:
                        current_solution['wastage'] += (sum(x) - shipping_request[item])
                    current_solution['number_of_containers'] += length_of_combination
                    current_solution['distribution'][item] = x
                    temp_request = shipping_request
                    del temp_request[item]
                    temp_list = list
                    for y in x:
                        temp_list.remove(y)
                    solution = find_the_best_solution(temp_request, temp_list, current_solution, best_shipping_solution)
                    if solution['wastage'] < best_shipping_solution['wastage']:
                        best_shipping_solution = solution
                    elif solution['wastage'] == best_shipping_solution['wastage']:
                        if solution['number_of_containers'] < best_shipping_solution['number_of_containers']:
                            best_shipping_solution = solution

    return best_shipping_solution   

This gives the following error- "Runtime error: dictionary size changed during iteration"

What am I doing wrong? How can I do it differently?

Sai Krishna
  • 7,647
  • 6
  • 29
  • 40
  • 1
    `list(combinations([0, 1, 2], 2))` gives you what you want. There's not enough context to help you - is `shipping_request` a dictionary, is this your actual code... What does your input data look like... – Jon Clements May 24 '13 at 08:03
  • Hi Jon, I've changed my question. Please have a look at it. – Sai Krishna May 24 '13 at 08:09

1 Answers1

1

This has nothing to do with itertools.combinations, you are trying to change the structure of data you are iterating over, which is not allowed:

Runtime error: dictionary size changed during iteration

You are trying to add or delete keys from a dictionary as you iterate it. A workaround is to iterate over for key in list(dictionary) which makes a copy list of the dictionary's keys, so you can still modify the underlying dictionary, however you may also want to reconsider your general approach.

The lines causing the error are:

for item in shipping_request:

    for i in range(0,len(list), 1):
            ...
            for x in combinations:
                if sum(x) >= shipping_request[item]:
                    if sum(x) > shipping_request[item]:
                        ...
                    temp_request = shipping_request
                    del temp_request[item] # you are trying to delete a key from 
                                           # shipping_request as you iterate it

Perhaps you want to make a shallow copy eg. temp_request = dict(shipping_request) which makes a new dictionary with references to the same objects. However you may want a import copy; copy.deepcopy to recursively copy every object inside the dictionary.

jamylak
  • 128,818
  • 30
  • 231
  • 230
  • Thanks @jamylak for replying. I've changed my question to display the whole function. Can you identify how I can improve this? – Sai Krishna May 24 '13 at 08:09
  • 1
    @ZachWild I've identified the error for you – jamylak May 24 '13 at 08:33
  • Awesome thanks. I didn't know about this concept of a shallow copy. I thought temp_request would be a different variable. Kind of funny but thanks so much. I can get on with my work. – Sai Krishna May 24 '13 at 08:37
  • @ZachWild I also showed a `copy.deepcopy` way, because if you are mutating the objects inside the dictionary, you will mutations occurring in other dictionaries as well – jamylak May 24 '13 at 08:42