0

I'm looping through a CSV, and would like to change "Gotham" to "Home". I've tried a couple ways, after searching around online, but can't seem to get it to work.

import csv

csv_file = "test.csv"

def process_csv(file):
    headers=[]
    data = []
    csv_data = csv.reader(open(file))
    for i, row in enumerate(csv_data):
        if i == 0:
            headers = row
            continue;
        field = []
        for i in range(len(headers)):
            field.append((headers[i],row[i]))
        data.append(field)
    return data

def create_merge_fast(city, country, contact):
    lcl = locals()

    ## None of these do what I'd think - if city is "Gotham" change it to "Home"
    for key, value in lcl.items():
        if value == "Gotham":
            lcl[value] = "Home"
        print(key, value)

    for value in lcl.values():
        if value == "Gotham":
            lcl[value] = "Home"
        print(value)

def set_fields_create_doc(data):
    city = data[4][1]
    country = data[6][1]
    contact = data[9][1]
    create_merge_fast(city, country, contact)

data = process_csv(csv_file)

for i in data:
    set_fields_create_doc(i)

I always seem to get

RuntimeError: dictionary changed size during iteration

right after Gotham is printed...

BruceWayne
  • 22,923
  • 15
  • 65
  • 110

2 Answers2

2

You cannot change your dict while iterating over it - the moment you change its state the iterator in for..in loop becomes invalid so it will pop the error from the title.

You can simply fix that by stopping the iteration once the match is found and changes were made to the dict, i.e.

for key, value in lcl.items():
    if value == "Gotham":
        lcl[key] = "Home"
        break  # exit here
    print(key, value)

However, if it's possible to have multiple items that match this condition, simply breaking away won't work, but you can freeze the key list instead before you start iterating through it:

for key in list(lcl.keys()):
    if lcl[key] == "Gotham":
       lcl[key] = "Home"
zwer
  • 24,943
  • 3
  • 48
  • 66
  • Thanks! It's a little confusing, again I'm just learning Python, but if `Gotham` is a `value`, then why do I do `lcl[key]` to change that value? I'm sure I'm missing something...does `[key]` become an index of some kind? Or does it mean like "that lcl key that has a value of 'Gotham', set that key value to 'Home'"? Where doing `lcl[value] = "Home"` would be "adding" a value to the key, trying to make `lcl[key]` equal to "Gotham" **and** "Home", thus changing the dictionary size? – BruceWayne Jun 23 '17 at 14:53
  • @BruceWayne - keys (and variables in general) in a dictionary don't really hold a value - they hold a pointer/reference to the memory location of the actual value (plus some more info, but it's irrelevant here). Since in Python strings are immutable (once created, you cannot change their value in-place) in order to change the value a certain key in a dictionary points to - you actually need to set it to point to another string. – zwer Jun 23 '17 at 15:04
  • Oh, I think I get it. And also, that kind of answers my next question I'm trying to figure out. After I change "Gotham" to "Home", when I try to then use `city` later in the function, it's still "Gotham". ...so now I'm looking at how do I use my updated value in the function...[this thread](https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) seems promising. Thanks again for your help! – BruceWayne Jun 23 '17 at 15:47
1

Change

lcl[value] = "Home"

to

lcl[key] = "Home"

The former will actually create a new entry in your dictionary with the key as "Gotham" and value as "Home", rather than modifying the existing value from "Gotham" to "Home".

So, you want:

for key in lcl:
    if lcl[key] == "Gotham":
        lcl[key] = "Home"
    print(key, lcl[key])

Also, you don't need the second loop.

cs95
  • 379,657
  • 97
  • 704
  • 746
  • Thanks for the info! Still learning, and trying to make more sense of using `[key]` instead of `[value]`, but I think I see what you're saying. (Yeah, the second loop was just showing two different ways I had originally tried to do it) – BruceWayne Jun 23 '17 at 14:56