Nested for loop over range() - python

For the following code:
x = range(10)
for i in x:
print(i)
for j in x:
print(">> %d" % j)
break
I would have expected the output to be:
0
>> 1
2
>> 3
..
but instead, it is:
0
>> 0
1
>> 0
2
>> 0
..
Why does range behave in this way?

By converting x to an iterator, you can achieve your expected behavior.
x = iter(range(10))
for i in x:
print(i)
for j in x:
print('> {}'.format(j))
break
which returns
0
> 1
2
> 3
4
> 5
6
> 7
8
> 9
What this shows us is that the problem does not lie with the breaking out of the inner loop per say but rather with range not being depleted as you loop over it. This happens because range is not an iterator and thus it restarts every time instead of picking up from where it left off.

for j in x:
print(">> %d" % j)
break
You are breaking the loop of J causing the value of J to reset and go back to 0 everytime.

Related

Python Nested Loop explanation

I’m new to python coding and i dont understand why the nested for loop is only returning 0 1 2 for the firs Iteration.
Input:
x = 3
for i in range (x):
for j in range (x):
x = 2
print (i, '',j)
Output:
0 0
0 1
0 2
1 0
1 1
2 0
2 1
x is changed after it's passed to range to make range(3). You only see the effects of the change (i.e. range(2)) on the next loop.
The Concept behind Nested for Loops:
Let us break this problem down (I am a beginner myself!)
x = 3
for i in range (x):
Now the range function has 3 parts (start, stop, step)
start: start from this number
stop: maximum value
step: increments by this value
when we say range(x); it assumes x=3 as the stop/max value of range. The start value is by default taken as 0, and the step value is by default taken as 1. So the range we get here is [0,1,2,3) {starts from 0 and stops at 3}
So the values that 'i' can take are 0,1,and 2 because 3 is max of the range; it is not included in the values i and j can take.
So output until this point:
for i in range (x):
for j in range (x):
(printing i and j separated by a whitespace)is:
0 0
0 1
0 2
0 is printed at the start and the loop is iterated 2 more times.
(you are getting all zeroes printed first for i as the statement you have written sends an instruction to print all the values of j for one value in the outer/main for loop; because loop for j is nested inside the loop for i)
Now, x= 2 means that from this point, values 'j' can take are 0,1. Hence the second part of the output:
1 0
1 1
Similarly, the the third part of the output is:
2 0
2 1
Hence the final output you get is:
0 0
0 1
0 2
1 0
1 1
2 0
2 1
Long version
In the for statement "for target in expression :" the second part is an iterable object.
range is not a 'reserved' word; it is the name of a built-in type(class) witch is iterable
Note : The syntax highlighter cheats if it highlights range as a reserved word. It does this, because this is generally useful as range is mainly used in association with for. But this does not change what range is. However, this can mislead you.
As a result of the above:
the correct typing is range(x) not range (x)
range(x) build an objet of type range and initialize it with x.
Short answer
x is interpreted when it is passed to range().
Code to print the range objects:
x = 3
range_i = range(x)
print(f"i loop x: {x}, range(x):{range_i}")
for i in range_i:
range_j = range(x)
print(f"j loop x: {x}, range(x):{range_j}")
for j in range_j:
x = 2
print(i, ' ',j)
Output
i loop x: 3, range(x):range(0, 3)
j loop x: 3, range(x):range(0, 3)
0 0
0 1
0 2
j loop x: 2, range(x):range(0, 2)
1 0
1 1
j loop x: 2, range(x):range(0, 2)
2 0
2 1
Rule of thumb
Unless you really know what you are doing, do not mess with the expression of the for statement.
lst = ['a', 'b', 'c', 'd']
for x in lst:
if x == 'b':
lst.remove('a')
print(x, end = ' ')
gives
a b d
And
lst = ['a', 'b', 'c', 'd']
for x in lst:
if x == 'd':
lst.insert(0, 'z')
print(x, end = ' ')
does not end and 'z' never appears:
a b c d d d d d d d d d d d d d ...
Musing around
Note : what follows is NOT recommended
You can redefine range. (The example below is a very simplified redefinition: it does not take in account the second version of range : range(start, stop[, step]) neither it cares for other range specifications)
def range(n):
i = 0
while i <= n: # note the use of '<=' instead of '<'
yield i
i += 1
And now 'range' does not behave as it should.
Example:
for i in range(3):
print(x, end = ' ')
gives:
0 1 2 3
Yes: 0..3 not 0..2 as the 'true' range.

How to reduce the nested for Loop complexity to a single loop in python?

for i in range(0,x):
for j in range(0,y):
if (i+j)%2 == 0:
Think of something like tossing two dices at the same time and finding if the sum on the dices is an even number but here's the catch, a dice has 6 sides but here the two can have any number of sizes, equal and not equal even!
Can anyone suggest how to merge it under one loop because I can't think of any?
based on Python combine two for loops, you can merge two for loops in a single line by importing itertools as below:
import itertools
for i, j in itertools.product(range(0,x), range(0,y)):
if (i+j)%2 == 0:
You can't get rid of the nested loop (you could hide it, like by using itertool.product, but it would still be executed somewhere, and the complexity would still be O(x * y)) but you can get rid of the condition, if you only need to generate the values of j that satisfy it, by adapting the range for j.
This way, you'll have about twice as less loops by avoiding the useless ones.
for i in range(0,x):
for j in range(i%2,y, 2):
print(i, j, i+j)
Output:
0 0 0
0 2 2
1 1 2
1 3 4
2 0 2
2 2 4
For me its much cleaner to leave it as two loops. Its much more readable and easier to understand whats happening. However you could essentially do x * y then use divmod to calculate i and j
x = 2
y = 3
for i in range(0,x):
for j in range(0,y):
print(i, j, i+j)
print("###")
for r in range(x*y):
i, j = divmod(r, y)
print(i, j, i + j)
OUTPUT
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
###
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3

skip the loop certain number of times if a condition satisfies in a for loop [duplicate]

This question already has answers here:
Skip multiple iterations in loop
(7 answers)
Closed 3 years ago.
I have a for loop in range(100).
Whenever I find a number that does satisfy a condition, it should skip a loop certain number of times
for i in range(2,100):
if i %2 != 0:
i = i+3
Expected results should be:
2
3
6
7
10
11
.
.
.
.
.
A for-loop does not allow you to skip multiple cycles. You can only use
continue to skip the rest of the current cycle
break to skip all remaining cycles and exit the loop
What you need is a while-loop. Where a for-loop defines a number that is incremented from a starting value up to a limit, a while-loop only needs an exit-condition.
Try this:
i = 2
while i < 100:
if i % 2 == 0:
i += 4
else:
i += 1
In my understanding this is what you want to do. But its not the output you desire. But I guess your expected output is not the output of your logic.
i = 2
while i<100:
print(i)
if i % 2 != 0:
i += 3
else:
i += 1
Outputs:
2
3
6
7
10
11
...
j = 0
for i in range(j,100):
if i%2 !=0:
j = i+3
continue
print(j)
output:
0
4
6
8
10
12
14
16
18
20
.
.
.
.
Actually i = i+3 has no effect in a for loop. you may think that i becomes 2+3=5 but in the next iteration i will be 3. You need to use a hile loop for this. This will do the trick for you:
i = 2
while i <= 100:
print(i)
i = (i + 3) if i % 2 != 0 else (i + 1)
Solution with a for loop (although I think a while loop is better for this):
skipping = 0
for i in range(2, 100):
if skipping:
skipping -= 1
continue
if i % 2 != 0:
print(i)
skipping = 2
else:
print(i)
Output:
2
3
6
7
10
11
...

A loop for adding list element without high memory performance?

Everybody,
a =[0, 0, 2, 4, 6]
x=5
This a list (a) and a fix value (x).
I need a loop codes which must add with x every element of list and add this value with previous list elements in every loop ( loop must continue as x value). Other words result should like below:
0
0
2
4
6
0
0
7
9
11
0
0
12
14
16
0
0
15
19
21
0
0
21
24
26
I prepared codes as below but it doesn’t work. Other words produce something as below (incorrect)
i=0
counter=0
while counter < x:
for i in a:
if i >0:
i=i+x
elif i ==0:
i=0
print i
counter=counter+1
0
0
7
9
11
0
0
7
9
11
0
0
7
9
11
0
0
7
9
11
0
0
7
9
11
So, I need to help for this…
Thank you.
I think this does mostly what you want (at least, as I understand the question)...
def make_it_so(a, x):
i = 0
counter=0
while counter < x:
for i in a:
if i == 0:
yield 0
else:
yield i + counter * x
counter = counter + 1
# Demo
for item in make_it_so([0, 0, 2, 4, 6], 5):
print item
Note that I've made it a generator function. You could easily turn it into a regular function that returns a list if you created an output list at the top of the function and swapped yield ... for output_list.append(...) and then return output_list at the end of the function...
The key here is to understand that in the first loop, you are adding 0 to all of the (non-zero) items. In the second loop, you are adding x. In the third loop, you're adding the x + x (since the first loop added x and now you're adding x more). In general, for the Nth loop, you'll be adding (N-1) * x to all of the non-zero items. So, you just need to keep track of N, (or N-1). In fact, your original code was already doing this (with counter), so we just re-purpose that and it's all good.
You need to change the values in a, not just add to the numbers you get out of a (because you'll keep getting the same ones out). Also, you need to print out the original values.
def process(x, memo):
return [n+x if n else n for n in memo]
res = a
memo = a
for _ in range(x - 1):
memo = process(x, memo)
res.extend(memo)

Using `for` in `range(x)` loop

Shouldn't both blocks of code print similar results? Why is the range function inside of the inner loop reevaluated each time the inner for statement is reached while the range function in the outerloop is only evaluated once?
x = 4
for j in range(x)
for i in range(x)
print i
x = 2
Results
0
1
2
3
0
1
0
1
0
1
I know the first 4 integers printed ( 0 - 3) are a result of the code
for j in range(x): code but why are the the following also printed?
0
1
0
1
0
1
The code
x = 4
for j in range(x):
print i
x = 5
Prints
0 1 2 3
Additional Info
Python 2.7 in IDLE
I can only explain by walking through the iterations of the loops, so here goes:
x = 4
for j in range(x)
for i in range(x)
print i
x = 2
First time through.
x = 4
for j in [0, 1, 2, 3]
for i in range [0, 1, 2, 3]
print i
x = 2
prints
0
1
2
3
Now x is set as 2, but the outer loops range has already been executed, so it is not reevaluated.
Code now becomes:
for j in [0, 1, 2, 3]:
for i in [0, 1]:
print i
x = 2
prints
0
1
And this continues two more times.
Function range(x) produces a list of [0,1,2,3,4]. In for loop you iterate over this list.
Your code is equivalent to:
for j in [0,1,2,3]:
for i in [0,1,2,3]:
print i
for i in [0,1]:
print i
for i in [0,1]:
print i
for i in [0,1]:
print i
range(x) is evaluated only once i.e. when the loop begins, that is why modifying x inside the loop has no effect.
However, in the first code clock, you change x to 2 in the inner, so the next time the inner loop is executed, range only gives (0,1).
Edit: your first block of code is equivalent to
x = 5
for i in range(x)
print i
x = 2
Here is how I view it:
Inner loop is executed for each iteration of outer loop
x = 4
j = 0
for i in range (x):
print(i)
x = 2
j = 1
for i in range(x) # this x is no longer 4 but it is 2
print(i)
x = 2
j = 2
for i in range (x): # this x is, of course, 2
print(i)
x = 2
j = 3
for i in range (x): # this x is, of course, 2
print(i)
x = 2
j is not printed, insert " print('xx', j, 'oo') " before " for i in range(x): "
then change to "print('xx', x, 'oo')
or change 'for j in range(x):' to 'for j in range(225,200,-5):' follow with 'print(j)' before 'for i in range(x):'

Categories