iFluctuate
iFluctuate

Reputation: 57

Decrement the Variable I'm Incrementing in for loop

kind of a newbie to Python and I've looked around a bit but haven't found a satisfying answer to my question. I'm doing some practice problems and I want to make a method that gets rid of duplicate values in a list. So far, this is my code:

def noDouble(nums):
  for x in xrange(len(nums) - 2):
      if nums[x] == nums[x + 1]:
          nums.pop(x)
          x -= 1
  return nums

What I want to happen is that if there's a duplicate, pop off one of the duplicates and then move back again (so that if there are, say, 3 instances of the same number, it'll get rid of al of them by 'rewinding').

I'm looking for an explanation for why my code doesn't work as well as an explained solution and I'd really appreciate any and all help. Thanks.

Upvotes: 0

Views: 2991

Answers (3)

TheSoundDefense
TheSoundDefense

Reputation: 6935

As far as I understand it, the for loop isn't a simple increment like it is in C or Java; Python will actually force x back to the value it's expected to be for the next loop iteration. So decrementing x won't have the effect of adding more loop iterations, because it will be forcibly reset.

for x in range(10):
x -= 1
print x

will yield

-1
0
1
2
3
4
5
6
7
8

EDIT: here's a possibility for what you're trying to do, though the accepted answer is easier for your specific use case. Use while instead of for:

limit = len(nums) - 1
x = 0
while x < limit:
  if nums[x] == nums[x+1]:
    nums.pop(x)
    x -= 1
  x += 1
return nums

Though this code may still fail with an IndexError because of how you're accessing list elements. But still, that's how you'd add extra iterations.

Upvotes: 2

Eevee
Eevee

Reputation: 48546

Because for doesn't count numbers; it iterates over a sequence. Every time the body of the loop executes, x is set to the next value produced by the xrange. The for statement couldn't care less what x is at the end of the loop.

You really shouldn't modify a list within a loop over it, anyway. The easier way to do this is to build a new list:

def remove_doubles(old):
    new = []
    for item in old:
        if new and item == new[-1]:
            continue
        new.append(item)
    return new

Of course, the really easy way to remove duplicates is list(set(foo)). But that will remove all duplicates, not just adjacent ones, and probably destroy the item order too.

Upvotes: 3

Kevin Seifert
Kevin Seifert

Reputation: 3572

Generally you never want to manipulate the counter in a loop (aside from setting it to break out of the loop). For a similar reason, you don't want to saw a branch you are sitting on, when cutting down a tree :-)

The safer route (compared to nested loops) is to build a set of operations in one loop, then pass this set to a second loop (each loop one level deep).

Upvotes: 0

Related Questions