Getting index in For Loop in python - python

Hi if i want to know when i reached the last iteration of my
for c in text:
In C it will seem like :
for (int i=0;i<strlen(str);i++)
if (i == strlen(str))
printf("The last index");

The idiomatic way to test whether a loop finished completely (i.e. exhausted its iterable) is to use for with else:
s = 'Hello World!'
for c in s:
# do something with character c, your code might break the loop
pass
else:
# the loop did not break, and iterated over all characters
print('The loop finished!')

My solution would be to create a counter outside the loop and increment it every time the loop iterates so you can have a reference of what the loop index is.
Check out the Python built-in function "enumerate", here is a link: http://book.pythontips.com/en/latest/enumerate.html

You can use the enumerate statement. It is written like this:
for index, val in enumerate(N):
if index + 1 == len(N):
print('The last index')

If you want see in console the state of your loop, you can use tqdm,
from tqdm import tqdm
for i in tqdm(range(N)):
#Some logic here

Related

How to restart a for loop

I have a piece of code. Here, I am running a for loop. If the if statement is not met, I want to restart that for loop. How should I do this? sp is a library btw.
for i in range (10000):
#my codes
a= sp.levene(#my variables)
if a[1] < 0.05:
#I want to restart for loop again
else:
#doing something
You probably don't want to use a for loop, since you aren't iterating over a particular sequence of numbers (i is going to jump around based on what happens inside the loop). Using a while you'd do:
i = 0:
while i < 10000:
# my code
a = sp.levene() # my variables
if a[1] < 0.05:
i = 0
continue
i += 1
# doing something
continue restarts the loop at the beginning of the loop body, and having set i = 0 it's now in the same state it was in at the first iteration.
The simplest way to handle this is:
while True:
for i in range(100000):
...
if a[1] < 0.05:
# this will exit out of the for loop, but the while
# loop will keep going
break
else:
....
# if we've successfully finished the "for" loop, then break out of
# the while loop
break
If your logic is a little bit more complicated:
done = False
while not done:
for i in range(100000):
...
if a[1] < 0.05:
# this will exit out of the for loop, but the while
# loop will keep going
break
else:
# set done to True if you've decided you don't need to perform
# the outer loop any more
other stuff
# likewise, set done to True if you're done with the outer while loop
To build on Frank Yellin's answer if you don't want to use break else break.
continueloop=True
while(continueloop):
for i in range (10000):
#my codes
a=sp.levene #my variables
if a[1] < 0.05:
#I want to restart for loop again
continueloop=True
else:
continueloop=False
#doing something
Hope you find a suitable answer!
I think what you are looking to do is have that function inside a loop. If the statement fails then on the else statement call the function again with new parameters. Basically, you want recursion on your loop is what I'm understanding.
def RecursionFunc() #3) when this function is called code runs from here
for i in range (10000):
#my codes
a= sp.levene(#my variables)
if a[1] < 0.05:
RecursionFunc() #2) will make you jump to the top again basically calling itself
break #4) will exit the current loop
else:
RecursionFunc() # 1)This will be the first code that gets executed
And the recursion will keep the function going and you can do plenty of other stuff with this. I know you want to break the loop and run again you can also change the "i" value on the next recursion run. If you give recursionFunc(int i) then you can basically set yours for loop to a new I value on the next run too. Can do a lot of cool things like this.

Transform a while loop with counter into a more pythonic code

Is there a way to trasform this python code into a more pythonic one?
i = 0
while condition:
doSomething()
i+=1
I use count for this type.
from itertools import count
c = count(0)
while condition:
doSomething()
next(c) # returns 0, +1 in further loops
But if you know how much loops you want, Try for loop.
for i in range(n):
doSomething()
If the condition is about the value of i like "i < 10", you can use "for" statement:
for i in range (10):
do_something ()
This will execute the function 10 times.
To second itzmeontv's answer, I personally do this:
for i in itertools.count():
if not condition:
break
do_something()
Note: Infinite loops are usually to be avoided if possible but, you know what's worse? Manual counters. Especially if they are at the bottom of the loop. That's why I put the condition check at the very top, right under the for loop statement.
However, if you know how many iterations you need, you can just use:
for i in range(100):
do_something()
And replace 100 by the desired amount of iterations.

Moving back an iteration in a for loop

So I want to do something like this:
for i in range(5):
print(i);
if(condition==true):
i=i-1;
However, for whatever reason, even though I'm decrementing i, the loop doesn't seem to notice. Is there any way to repeat an iteration?
for loops in Python always go forward. If you want to be able to move backwards, you must use a different mechanism, such as while:
i = 0
while i < 5:
print(i)
if condition:
i=i-1
i += 1
Or even better:
i = 0
while i < 5:
print(i)
if condition:
do_something()
# don't increment here, so we stay on the same value for i
else:
# only increment in the case where we're not "moving backwards"
i += 1
Python loop using range are by-design to be different from C/C++/Java for-loops. For every iteration, the i is set the the next value of range(5), no matter what you do to i in between.
You could use a while-loop instead:
i = 0
while i<5:
print i
if condition:
continue
i+=1
But honestly: I'd step back and think again about your original problem. Probably you'll find a better solution as such loops are always error-prone. There's a reason why Python for-loops where designed to be different.
You have a misunderstanding about loops in Python. The for loop doesn't care what you do with i at each iteration, because it is not related to the logic of the loop at all. Modifying i just rebinds a local variable.
You would need to use a while loop to achieve the behaviour you're expecting, where the state of i does affect the control flow of the loop:
import random
i = 0
while i < 5:
print(i)
i += 1
if random.choice([True, False]):
i -= 1
range(5) creates a list with numbers 0 thru 4 in it - [0, 1, 2, 3, 4].
When you run a for loop over it, you are iterating over the list. Doing i-= 1 will only decrement the value of that particular element of the list, and the iteration will continue.
Like the other answers here have suggested, you should use a while loop.
i= 0
while i<5:
# do stuff
if #condition:
i-= 1 # or +
i+= 1
Repeating many other answers, and just for completeness, you will need to use a while loop.
i = 0
while i < 5:
print(i)
if (not condition):
i+=1
If you want to move back an iteration in the loop (instead of repeating an iteration), then use this:
i = 0
while i < 5:
print(i)
if (condition):
i -= 1
else:
i += 1
Essentially, while i < 5 evaluates upon each iteration, and checks if i < 5. Thus by decrementing/not changing i, we get something like this: (values of i)
Not changing: 1->2->3-(condition satisfied)> 3 -> 4 -> 5
Decrementing: 1->2->3-(condition satisfied)>2 -> 3 -> 4 -> 5
The reason why i=i-1 in your for loop doesn't make it repeat the iteration is simple. In the for loop, i is assigned the value of the next item in the for loop. Python could care less about what you do with i, as long as it is able to assign the next item to it. Thus, the for loop for i in <your_iterable>:<do whatever> is closer to this:
_i = 0
_length = len(<your_iterable>)
while _i < _length:
i = _i
_i += 1
<do whatever>
However, in this analogy, you wouldn't be able to access the _ predicated variables (_i,_length). This is how I simplify the logic of the for loop. Note that regardless of what i is assigned to, it will be assigned to _i upon the next iteration, and the loop really doesn't care about what i is.
Utilize a while loop:
i = 0
while i < 5:
print(i)
if condition:
i -= 1
i += 1
As has been mentioned, this is rather unidiomatic Python. Perhaps if you post what you are trying to achieve we can give some better advice.
In Python it's possible to set up a two-way exchange between an iterator (what comes after in in a for..in loop) and its consumer (code inside the loop). To achieve this, you can use send in the consumer code to "inject" a value in a generator. In your case, you can simply send back the current value once the condition is met and wrap the range call in a generator that repeats whatever is sent back to it. Here's some code for you to play, intentionally verbose for clarity:
def repeateble(it):
buf, it = None, iter(it)
while True:
if buf is None:
# the buffer is empty, send them the next elem
val = next(it)
else:
# there's something in the buffer
# let's send that back
val = buf
# send the value and wait what they say
back = yield val
if back:
# they've sent us something!
# give them some dummy value as a result of send()
yield None
# and save what they've sent in a buffer
# for the next iteration
buf = back
else:
# they haven't sent anything
# empty the buffer
buf = None
from random import randint
# create a repeateble generator
rng = repeateble(range(100))
for x in rng:
print(x)
# check "some condition"...
if randint(1, 100) > 80:
print('repeat:')
# send the current value back to the generator
# it will be returned on the next iteration
rng.send(x)
You can use readlines if you're iterating through a file and pull out the previous lines based on a condition.
with open("myfile.txt", "r") as f:
text = f.readlines()
for row in range(0, len(text)):
if re.search("Error", text[row]):
print(text[row-1].strip())

Looping from 1 to infinity in Python

In C, I would do this:
int i;
for (i = 0;; i++)
if (thereIsAReasonToBreak(i))
break;
How can I achieve something similar in Python?
Using itertools.count:
import itertools
for i in itertools.count(start=1):
if there_is_a_reason_to_break(i):
break
In Python 2, range() and xrange() were limited to sys.maxsize. In Python 3 range() can go much higher, though not to infinity:
import sys
for i in range(sys.maxsize**10): # you could go even higher if you really want
if there_is_a_reason_to_break(i):
break
So it's probably best to use count().
def to_infinity():
index = 0
while True:
yield index
index += 1
for i in to_infinity():
if i > 10:
break
Simplest and best:
i = 0
while not there_is_reason_to_break(i):
# some code here
i += 1
It may be tempting to choose the closest analogy to the C code possible in Python:
from itertools import count
for i in count():
if thereIsAReasonToBreak(i):
break
But beware, modifying i will not affect the flow of the loop as it would in C. Therefore, using a while loop is actually a more appropriate choice for porting that C code to Python.
Reiterating thg435's comment:
from itertools import takewhile, count
def thereIsAReasonToContinue(i):
return not thereIsAReasonToBreak(i)
for i in takewhile(thereIsAReasonToContinue, count()):
pass # or something else
Or perhaps more concisely:
from itertools import takewhile, count
for i in takewhile(lambda x : not thereIsAReasonToBreak(x), count()):
pass # or something else
takewhile imitates a "well-behaved" C for loop: you have a continuation condition, but you have a generator instead of an arbitrary expression. There are things you can do in a C for loop that are "badly behaved", such as modifying i in the loop body. It's possible to imitate those too using takewhile, if the generator is a closure over some local variable i that you then mess with. In a way, defining that closure makes it especially obvious that you're doing something potentially confusing with your control structure.
If you want to use a for loop, it's possible to combine built-in functions iter (see also this answer) and enumerate for an infinite for loop which has a counter. We're using iter to create an infinite iterator and enumerate provides the counting loop variable. The start value is zero by default, but you can set a different start value with the start argument.
for i, _ in enumerate(iter(bool, True), start=1):
input(i)
Which prints:
1
2
3
4
5
...
If you're doing that in C, then your judgement there is as cloudy as it would be in Python :-)
For a loop that exits on a simple condition check at the start of each iteration, it's more usual (and clearer, in my opinion) to just do that in the looping construct itself. In other words, something like (if you need i after loop end):
int i = 0;
while (! thereIsAReasonToBreak(i)) {
// do something
i++;
}
or (if i can be scoped to just the loop):
for (int i = 0; ! thereIsAReasonToBreak(i); ++i) {
// do something
}
That would translate to the Python equivalent:
i = 0
while not there_is_a_reason_to_break(i):
# do something
i += 1
Only if you need to exit in the middle of the loop somewhere (or if your condition is complex enough that it would render your looping statement far less readable) would you need to worry about breaking.
When your potential exit is a simple one at the start of the loop (as it appears to be here), it's usually better to encode the exit into the loop itself.
def infinity():
i=0
while True:
i+=1
yield i
for i in infinity():
if there_is_a_reason_to_break(i):
break
def natural_numbers():
yield from map(sum, enumerate(iter(int,1)))
for i in natural_numbers():
if there_is_a_reason_to_break(i):
break;

Python - Way to restart a for loop, similar to "continue" for while loops? [duplicate]

This question already has answers here:
python: restarting a loop
(5 answers)
Closed 7 years ago.
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!
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).
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.
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'] ) )
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'])]
Continue will work for any loop.
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
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
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

Categories