Search code examples
pythonloopsdeque

Unexpected behavior adding and removing items from a deque in a loop


The problem I am having is in the function arrangeNodes(). It seems to add extraneous values to the dict I passed to it as an arguement. The dict 'stops' is filled by using values in 'foo' which are in a certain range. I have showed below that the maximum amount of values in foo at any time is 3. Since the function iterates once over the keys in the dict, each key is only used once in the first for-loop and in the second for-loop, the set associated with the key can only contain a maximum of 3 values.

However after the function has executed, I suddenly have more than 3 values in each set in the dict

#!/usr/bin python
from collections import deque

d_min = int(raw_input())
d_max = int(raw_input())

def arrangeNodes(keys, stops):
    foo = deque()
    for r in keys:
        k = r + d_max
        while len(foo) and k < foo[0]: foo.popleft()
        for num in foo:
            if d_min <= num - r <= d_max: stops[r].add(num)
            else: break
        foo.append(r)
    return  


ans = 0
motels = {}.fromkeys([7000, 6010, 5990, 5030, 4970, 4060, 3930, 3060, 2940, 2030, 1970, 1010, 990, 0], set())
motels.update({}.fromkeys((int(raw_input()) for _ in xrange(int(raw_input()))), set()))
print motels #All sets in this dict are empty before the function call
arrangeNodes(sorted(motels.iterkeys(), reverse=True), motels)
for v in motels:
    print v, motels[v]

Sample input: 970, 1040, 0

With this input, the maximum length of the container 'foo' should never exceed 3. Here are the values in foo for each iteration in the function:

deque([])
deque([7000])
deque([7000, 6010])
deque([6010, 5990])
deque([6010, 5990, 5030])
deque([5030, 4970])
deque([4970, 4060])
deque([4060, 3930])
deque([3930, 3060])
deque([3060, 2940])
deque([2940, 2030])
deque([2030, 1970])
deque([2030, 1970, 1010])
deque([1010, 990])

Therefore the dict 'motels' should not have more than 3 values in the sets it contains. But whenever I run this program, I get the following output when I print motel after the function has executed:

0 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
5990 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
5030 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
2940 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
4970 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
1010 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
2030 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
1970 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
3060 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
7000 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
6010 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
4060 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
3930 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])
990 set([5990, 5030, 2940, 4970, 1010, 2030, 1970, 3060, 7000, 6010, 4060, 3930, 990])

I don't understand why this is. Can someone explain?


Solution

  • I find your code a bit hard to read, since it is not entirely clear what you want to do. I Assume however, that you don't want a dict with items that all point to the same set instance, which is the case after

    motels = {}.fromkeys([7000, 6010, 5990, 5030, 4970, 4060, 3930, 3060, 2940, 2030, 1970, 1010, 990, 0], set())
    

    If you do for example:

    >>> motels[7000].add(1)
    >>> print motels[0]
        set([1])
    

    because all keys are pointing to the same item. After updating your dict with the user supplied information, there will be another set instance, which is however irrelevant for your sample input of 0. Try this

    motels = dict([(i, set()) for i in [7000, 6010, 5990, 5030, 4970, 4060, 3930, 3060, 2940, 2030, 1970, 1010, 990, 0]])
    

    to initialize your motels. This will create a set instance for each key. Then do

    for i in xrange(int(raw_input())): motels[int(raw_input())] = set()
    

    for the updating of the motels (which is also more readable in my opinion).