Proper deletion of selected items during map iteration in for loop

Peter Otten __peter__ at web.de
Sat Apr 26 17:30:57 EDT 2014


Charles Hixson wrote:

> What is the proper way to delete selected items during iteration of a
> map?  What I want to do is:
> 
> for (k, v) in m.items():
>     if f(k):
>        #  do some processing of v and save result elsewhere
>        del m[k]
> 
> But this gives (as should be expected):
>          RuntimeError: dictionary changed size during iteration
> In the past I've accumulated the keys to be deleted in a separate list,
> but this time there are likely to be a large number of them, so is there
> some better way?

It just struck me that you can store the keys to be deleted as values in the 
same dict. That way you need no extra memory:

def delete_items(d, keys):
    keys = iter(keys)
    try:
        first = prev = next(keys)
    except StopIteration:
        return

    for key in keys:
        d[prev] = prev = key
    d[prev] = first

    key = first
    while True:
        key = d.pop(key)
        if key is first:
            break

if __name__ == "__main__":
    import string
    data = dict(zip(range(10), string.ascii_lowercase))
    print("original data:", data)
    print("removing odd items...")
    delete_items(data, keys=(k for k in data if k % 2))
    print("modified data:", data)

    print("delete no items...")
    delete_items(data, [])
    print("modified data:", data)

    print("delete a single item (6)...")
    delete_items(data, [6])
    print("modified data:", data)

    print("delete all items...")
    delete_items(data, data)
    print("modified data:", data)

While I think I am a genius* in practice this approach will probably not be 
the most effective.

(*) (Un)fortunately that feeling never lasts longer than a few minutes ;)




More information about the Python-list mailing list