Omkar
Omkar

Reputation: 21

Python - Add new entries to dictionary while iterating over another dictionary

I want to check if there is an overlap between points in one dictionary with another. If there is no overlap, then create a new key in the dictionary with the value. I am getting an error while implementing the following code.

RuntimeError: dictionary changed size during iteration


for k1 in d1:
    for k2 in d2:
        if(overlap(k1,k2)==False):
            d2[len(d2)+1]=d1[k1]                

Is there another way to implement this?

Edit:

d1 = {"file1":[2,3],"file2":[11,15]}
d2 = {1:[1,5],2:[6,10]}

Output:

d2 = {1:[1,5],2:[6,10],3:[11,15]}

Upvotes: 0

Views: 1342

Answers (4)

Clade
Clade

Reputation: 986

I believe you are looking for dict.update():

d1 = {'foo': 0,
      'bar': 1}

d2 = {'foo': 0,
      'bar': 1,
      'baz': 2}

d1.update(d2)

This results in:

d1 = {'foo': 0,
      'bar': 1,
      'baz': 2}

Edit:

import itertools

d1 = {"file1":[2,3],
      "file2":[11,15]}

d2 = {1:[1,5],
      2:[6,10]}

d2 = {**d2, **{max(d2.keys())+i+1: v for i, (k, v) in enumerate({k: v for k, v in d1.items() if not any(i in range(v[0], v[1]+1) for i in itertools.chain.from_iterable(range(v[0], v[1]+1) for v in d2.values()))}.items())}}

Produces:

d2 = {1: [1, 5],
      2: [6, 10],
      3: [11, 15]}

😃

Upvotes: 2

b_c
b_c

Reputation: 1212

Based on your description, edit, and comments it doesn't sound like dict.update() will give you the results you want.

The error you're hitting is because the loop makes an assumption of the number of items it will be iterating once it starts up. During the loop, you change that number, invalidating the assumption, causing the the program to fail.

To fix this, you need to iterate a copy of the items instead. You also mentioned you're concerned with the values and not the keys, so you need to adjust what you're iterating as well.

Now, you didn't actually post what your overlap function does, so I'm assuming something like this based on your comments/sample:

def overlap(left, right):
    return left[0] - right[-1] == 1

For the most part, the actual implementation of your overlap is irrelevant to the question, but the code above at least gave me your expected output.

I've then adjusted your code to the following:

for v1 in list(d1.values()):
    for v2 in list(d2.values()):
        # If v1 overlaps v2
        if overlap(v1, v2):
            # Add v1 to d2 under the next sequential key
            d2[len(d1) + 1] = v1

By using list(d1.values()), I'm no longer iterating the dictionary itself while modifying it - I'm taking a "snapshot" of the contents (the values specifically here) at the start of the loop.

Using this and your sample data, d2 contains {1: [1, 5], 2: [6, 10], 3: [11, 15]} after the loop.

Upvotes: 0

Steve Mapes
Steve Mapes

Reputation: 921

If you are trying to merge dictionaries then the faster way is using one of these

a = dict(one=1,two=2,three=3,four=4,five=5,six=6)
b = dict(one=1,two=2,three=5,six=6, seven=7, nine=9)
a.update(b)

Which gives {'one': 1, 'two': 2, 'three': 5, 'four': 4, 'five': 5, 'six': 6, 'seven': 7, 'nine': 9}

Or you can use c = dict(a, **b)

Upvotes: 1

David Kaftan
David Kaftan

Reputation: 2174

You don't need a double loop there. Loop through the keys in d1. Check if d2.keys contains k1. If not, add k1 to d2. I don't have the syntax right here, but something along these lines.

for k1 in d1.keys:
    if not k1 in d2.keys:
        d2[k1] = d1[k1]

return d2

Upvotes: 0

Related Questions