15

Basically, I need a way to return control to the beginning of a for loop and actually restart the entire iteration process after taking an action if a certain condition is met.

What I'm trying to do is this:

    for index, item in enumerate(list2):
    if item == '||' and list2[index-1] == '||':
        del list2[index]
        *<some action that resarts the whole process>*

That way, if ['berry','||','||','||','pancake] is inside the list, I'll wind up with:

['berry','||','pancake'] instead.

Thanks!

Georgina
  • 381
  • 1
  • 6
  • 13
  • Are you asking about nested loops? `while something: for ...`? If so, what's so complex? Please post a code sample to show what you're doing. – S.Lott Sep 13 '10 at 22:41
  • Can you provide some sample code so we can figure out what you're asking. "continue" works for both "for" and "while" loops. It looks like you want something different. – Aaron D Sep 13 '10 at 22:43
  • 5
    continue does not do this for while loops it merely skips the rest of the loop body, just as it does with for loops. Try rephrasing your question to describe what you're trying to accomplish instead of how you're trying to accomplish it – Geoff Reedy Sep 13 '10 at 22:43
  • Yeah, I really have to wonder why you're trying to do this. Perhaps there's a better solution, if you look at the big picture. – David Z Sep 13 '10 at 22:47
  • Thanks guys. I've edited the original post with a code sample that explains what I'm trying to do! – Georgina Sep 13 '10 at 22:48
  • While THC4k doesn't answer the question, it is a good way to solve your original problem. If you insist on deleting items from the list, you are better off to just use a single while loop and managing the index yourself – John La Rooy Sep 13 '10 at 23:36

8 Answers8

43

I'm not sure what you mean by "restarting". Do you want to start iterating over from the beginning, or simply skip the current iteration?

If it's the latter, then for loops support continue just like while loops do:

for i in xrange(10):
  if i == 5:
    continue
  print i

The above will print the numbers from 0 to 9, except for 5.

If you're talking about starting over from the beginning of the for loop, there's no way to do that except "manually", for example by wrapping it in a while loop:

should_restart = True
while should_restart:
  should_restart = False
  for i in xrange(10):
    print i
    if i == 5:
      should_restart = True
      break

The above will print the numbers from 0 to 5, then start over from 0 again, and so on indefinitely (not really a great example, I know).

Liquid_Fire
  • 6,990
  • 2
  • 25
  • 22
26
while True:
    for i in xrange(10):
        if condition(i):
            break
    else:
        break

That will do what you seem to want. Why you would want to do it is a different matter. Maybe you should take a look at your code and make sure you're not missing an obvious and easier way to do it.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
  • 3
    As clarification (since `for: ... else:` can be kind of confusing and this also has `break`s in two nested loops): if the condition is true, it breaks out of the `for` loop, which means it skips the `else` part of that loop, which means it goes back to the top of the `while` loop. If the condition is always false, it completes the `for` loop, goes into the `else` part, and `break`s from the `while` loop. – Vivian Sep 02 '16 at 17:00
5

some action that resarts the whole process

A poor way to think of an algorithm.

You're just filtering, i.e., removing duplicates.

And -- in Python -- you're happiest making copies, not trying to do del. In general, there's very little call to use del.

def unique( some_list ):
    list_iter= iter(some_list)
    prev= list_iter.next()
    for item in list_iter:
        if item != prev:
            yield prev
            prev= item
    yield prev

list( unique( ['berry','||','||','||','pancake'] ) )
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • He's removing adjacent duplicates, to be clear. It seems this is what your method does, but it's not what is generally meant by the name 'unique'. – David M. Sep 13 '10 at 22:58
  • @David M.: While true, that's a kind of "negative" comment. "unique isn't appropriate". Okay. What do you suggest? Can you make a "positive" comment that proposes something? – S.Lott Sep 13 '10 at 23:15
  • Sure, if you need that kind of coddling. (For what it's worth, I upvoted your answer; I'm not trying to tear you down, just don't want the OP to be confused.) The `itertools` recipes call it `unique_justseen`, perhaps `unique_adjacent` would be better. – David M. Sep 13 '10 at 23:56
  • @David M: "trying to tear you down" What? You pointed out a possible error. Why not take the next logical step and make a suggestion? It's not "coddling" -- it's an approach to providing value. Saying something is "not what is generally meant" has minimal value. Improving on an answer adds more value. Pointing out an error doesn't add as much value. I'm not asking for coddling. I'm asking you to create as much value as possible. You must have some insight. Share it. – S.Lott Sep 14 '10 at 01:03
  • 2
    My apologies, I took your comment the wrong way. It's probably from being surrounded by HR people. – David M. Sep 14 '10 at 01:57
4

The inevitable itertools version, because it just came to me:

from itertools import groupby

def uniq(seq):
    for key, items in groupby(seq):
        yield key

print list(uniq(['berry','||','||','||','pancake'])) # ['berry','||', 'pancake']
# or simply:
print [key for key, items in groupby(['berry','||','||','||','pancake'])]
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
3

Continue will work for any loop.

volting
  • 16,773
  • 7
  • 36
  • 54
  • But I'm looking for a way to restart the for loop entirely...control goes back to the state it was in at the beginning. – Georgina Sep 13 '10 at 22:39
  • Good reference for this: http://en.wikibooks.org/wiki/Python_Programming/Flow_control#Breaking.2C_continuing_and_the_else_clause_of_loops – Aaron D Sep 13 '10 at 22:41
3

continue works in for loops also.

>>> for i in range(3):
...     print 'Before', i
...     if i == 1:
...             continue
...     print 'After', i
... 
Before 0
After 0
Before 1
# After 1 is missing
Before 2
After 2
Sam Dolan
  • 31,966
  • 10
  • 88
  • 84
  • Thanks--that's good to know! But I'm looking for a way to restart the for loop entirely...control goes back to the state it was in at the beginning. – Georgina Sep 13 '10 at 22:40
1

As you can see answering your question leads to some rather convoluted code. Usually a better way can be found, which is why such constructs aren't built into the language

If you are not comfortable using itertools, consider using this loop instead. Not only is it easier to follow than your restarting for loop, it is also more efficient because it doesn't waste time rechecking items that have already been passed over.

L = ['berry','||','||','||','pancake']
idx=1
while idx<len(L):
    if L[idx-1]==L[idx]:
        del L[idx]
    else:
        idx+=1
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
0
def remove_adjacent(nums):
     return [a for a,b in zip(nums, nums[1:]+[not nums[-1]]) if a != b]

example = ['berry','||','||','||','pancake']

example = remove_adjacent(example)
print example
""" Output:
['berry', '||', 'pancake']
"""

And by the way this is repeating of Remove adjacent duplicate elements from a list

Community
  • 1
  • 1
Tony Veijalainen
  • 5,447
  • 23
  • 31