2

So my issue is with this not incrementing correctly... I tried to uses an int "step" to + 1 every time this loop is ran but it doesn't do anything. Why is that? Also when I print(step) it only adds up to 337. It does not go the full 1000 like I had thought I asked it too. How do I do this correctly?

lockers = []

step = 3

locker = 0

while len(lockers) <= 1000:
     lockers.append(1)

for i in range(0, len(lockers)):
     lockers[i] = 0

for i in range(0, len(lockers), 2):
     lockers[i] = 1

for i in range(0, len(lockers), step):
     if lockers[i] == 0:
          lockers [i] = 1
     else:
          lockers[i] = 0

     step += 1


print(lockers)
5
  • 1
    Generally, range() and enumerate() usage is considered more pythonic, but it really depends on your individual use case. In this case it's not real clear what the end intension is. What is your end goal? Commented Oct 10, 2015 at 4:49
  • range(0, len(lockers), step) is only called once, with the initial values. Commented Oct 10, 2015 at 4:50
  • check out documentation docs.python.org/2/library/functions.html#range , changing step does not affect the loop Commented Oct 10, 2015 at 4:51
  • How can I call it again? Commented Oct 10, 2015 at 4:51
  • Can you tell what your exact goal?? Commented Oct 10, 2015 at 5:08

2 Answers 2

2

range gives you an iterable object:

>>> range(10,20 , 2)
range(10, 20, 2)
>>> list(range(10,20 , 2))
[10, 12, 14, 16, 18]

The values in it are fully decided as soon as the call returns, and aren't re-evaluated each time around the loop. Your step only goes up to 337 because you are incrementing it once for each element in the object range(0, 1000, 3), which has 334 items, not 1000:

>>> len(range(0,1000,3))
334

To get something that works like range but advances the step, you would need to write your own generator:

def advancing_range(start, stop, step):
    ''' Like range(start, stop, step) except that step is incremented 
        between each value 
    '''
    while start < stop:
        yield start
        start += step
        step += 1

You can then do for i in advancing_range(0, 1000, 3): and it will work as you intend.

But this is a very strange thing to want to do. Judging by your variable names, I would guess you're coding the locker problem, which says:

A new high school has just been completed. There are 1,000 lockers in the school and they have been numbered from 1 through 1,000. During recess (remember this is a fictional problem), the students decide to try an experiment. When recess is over each student will walk into the school one at a time. The first student will open all of the locker doors. The second student will close all of the locker doors with even numbers. The third student will change all of the locker doors that are multiples of 3 (change means closing lockers that are open, and opening lockers that are closed.) The fourth student will change the position of all locker doors numbered with multiples of four and so on. After 1,000 students have entered the school, which locker doors will be open, and why?

But the advancing range logic says something more like "the first student opens the first locker, then the second opens the second locker after that, then the third student opens the third locker after that ...". You want to affect multiple lockers each time, but further spaced out. Essentially, you want to copy and paste your first two loops another 998 times with a one higher step each time. Of course, you can do better than copy and paste, and this seems like you want two nested loops, where the outer one advances the step that the inner one uses. That would look like this:

for step in range(1, len(lockers)):
    for i in range(step, len(lockers), step):

Simplifying your other logic by using booleans instead of 1 and 0, the whole program looks like this:

lockers = [True] * 1000

for step in range(1, len(lockers)):
    for i in range(step, len(lockers), step):
        lockers[i] = not lockers[i]

print(sum(lockers))

It prints that the number of open lockers is 969.

Sign up to request clarification or add additional context in comments.

3 Comments

My end goal is to have only about 32 0s and 968 1s. Maybe my instructor made a mistake? I doubt it but its possible.
@Casey check that your logic matches what your instructor has said. As far as I can tell, your logic, once working, leads to 501 1s. But without your first two loops (ie, start all the lockers set to 0 and then do the advancing_range loop), I get 43 1s. Using nested loops to do multiple ranges with different steps instead (which I will add to my answer), I get 31 1s, which is close to the opposite of what you want.
@Casey check my updated answer, which directly addresses what I think you're trying to do.
0

If you want to adjust the step size while iterating, you can have an own range object:

class AdjustableRange(object):
    def __init__(self, start, stop, step):
        self.start = start
        self.stop = stop
        self.step = step
        self.value = None
    def __iter__(self):
        if self.value is None:
            self.value = start
        while self.value < self.stop:
            yield self.value
            self.value += self.step

This (untested) one you can use for iterting like

rg = AdjustableRange(0, len(lockers), step):
for i in rg:
    if lockers[i] == 0:
        lockers [i] = 1
    else:
        lockers[i] = 0
    rg.step += 1 # this influences the iteration

But, as was already said, there are better ways to solve your "real" problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.