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

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):'

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.

What does this list comprehension do?

dp = [[0 for x in range(m+1)] for x in range(n+1)]
Can someone explain this code what actually happens in this part of the code? I think this involves list comprehensions.
dp = [[0 for x in range(m+1)] for x in range(n+1)]
This is equivalent to
for x in range(n+1):
for x in range(m+1):
dp = 0
This will create a 2D array of size (n + 1) x (m + 1). Suppose, n = 2, and m = 3. Then, the outer loop will run for 3 times, and for each time the outer loop runs, the inner loop will run 4 times. So, it will make a list [0 0 0 0]```` (in the inner loop). Now, as the inner loop is executing thrice, there will be 3 lists[0 0 0 0] [0 0 0 0] [0 0 0 0]```, and they will altogether form a 3 x 4 matrix.
This can be better understood as
for x in range(3):
for x in range(4):
print(0, end = ' ')
print()
The above snippet outputs
0 0 0 0
0 0 0 0
0 0 0 0
Basically dp will be a 2D-Matrix of dimension(n+1,m+1).
[0 for x in range(m+1)] : this create a list of size (m+1) initialized with zeros.
For example: if m=2, list will be [0,0,0]
[[0 for x in range(m+1)] for x in range(n+1)] : Now when we see the whole code
together, we will get a 2D list.
For example, if n=2, dp will be [[0,0,0], [0,0,0], [0,0,0]]

Nested for loop over range()

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.

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)

How to create lists of 3x3 sudoku block in python

I need help creating a list for each of the 9 3x3 blocks in sudoku. so I have a list of lists representing the original sudoku board (zero means empty):
board=[[2,0,0,0,0,0,0,6,0],
[0,0,0,0,7,5,0,3,0],
[0,4,8,0,9,0,1,0,0],
[0,0,0,3,0,0,0,0,0],
[3,0,0,0,1,0,0,0,9],
[0,0,0,0,0,8,0,0,0],
[0,0,1,0,2,0,5,7,0],
[0,8,0,7,3,0,0,0,0],
[0,9,0,0,0,0,0,0,4]]
I need to turn these into a list of lists containing the 3x3 blocks. So for example:
[[2,0,0,0,0,0,0,4,8],[etc]]
i tried creating one list called "blocks" containing 9 other lists with just zeroes in each list. so it looked like:
blocks=[[0,0,0,0,0,0,0,0,0],[etc]
then i used a while loop to change the values in the list:
BLOCK_COUNT=0
BOARD_COUNT=0
while BLOCK_COUNT<len(blocks):
blocks[BLOCK_COUNT][0]=board[BOARD_COUNT][BOARD_COUNT]
blocks[BLOCK_COUNT][1]=board[BOARD_COUNT][BOARD_COUNT+1]
blocks[BLOCK_COUNT][2]=board[BOARD_COUNT][BOARD_COUNT+2]
blocks[BLOCK_COUNT][3]=board[BOARD_COUNT+1][BOARD_COUNT]
blocks[BLOCK_COUNT][4]=board[BOARD_COUNT+1][BOARD_COUNT+1]
blocks[BLOCK_COUNT][5]=board[BOARD_COUNT+1][BOARD_COUNT+2]
blocks[BLOCK_COUNT][6]=board[BOARD_COUNT+2][BOARD_COUNT]
blocks[BLOCK_COUNT][7]=board[BOARD_COUNT+2][BOARD_COUNT+1]
blocks[BLOCK_COUNT][8]=board[BOARD_COUNT+2][BOARD_COUNT+2]
BLOCK_COUNT+=1
BOARD_COUNT+=3
This however gives me an index error. if I create 2 of those while loops with "BLOCK_COUNT" being 3 and 6 respectively then i get a better answer but it still doesn't give me the correct 3x3 block for some. So i'm pretty much at a loss for how to do this. Thanks.
def getBlocks(board):
answer = []
for r,c in itertools.product(range(3), repeat=2):
answer.append([board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)])
return answer
Of course, you could replace the whole thing with just one list comprehension:
answer = [[board[r+i][c+j] for i,j in itertools.product(range(0, 9, 3), repeat=2)]
for r,c in itertools.product(range(3), repeat=2)]
In case you are interested in a version that doesn't use any built-ins to do any heavy lifting:
def getBlocks(board):
answer = []
for r in range(3):
for c in range(3):
block = []
for i in range(3):
for j in range(3):
block.append(board[3*r + i][3*c + j])
answer.append(block)
return answer
So what's happening here?:
Well, first, we decide to iterate over the 9 blocks that we want. These are governed by the r and c variables. This is also why we multiply them by 3 when we access the numbers on the board (because each block is a square of side 3).
Next, we want to iterate over the elements in each block. Translation: Lookup the numbers within each 3x3 block. The index of each element within the block is governed by i and j. So we have i and j that govern the elements we want to access, along with r and c, which are their offsets from the board itself, determining the location of the "block" we want. Now we're off to the races.
For each r and c (notice that each loops over range(3), so there are 9 (r,c) pairs - the 9 blocks that we are after), loop over the 9 elements in the block (the 9 (i,j) pairs). Now, simply access the elements based on their relative locations from the (r,c) offsets (3*r gives the first row of the relevant block, and adding i gives the row of the required element. Similarly, 3*c gives the first column of the relevant block, and adding j gives the column of the required element. Thus, we have the coordinates of the element we want). Now, we add the element to block.
Once we've looped over all the elements in the block, we add the block itself to the answer, and presto! we're done
You can do this with a combination of reshape and transpose when you use numpy.
edit - sorry - hit enter too soon:
import numpy as np
board=[[2,0,0,0,0,0,0,6,0],
[0,0,0,0,7,5,0,3,0],
[0,4,8,0,9,0,1,0,0],
[0,0,0,3,0,0,0,0,0],
[3,0,0,0,1,0,0,0,9],
[0,0,0,0,0,8,0,0,0],
[0,0,1,0,2,0,5,7,0],
[0,8,0,7,3,0,0,0,0],
[0,9,0,0,0,0,0,0,4]]
t = np.array(board).reshape((3,3,3,3)).transpose((0,2,1,3)).reshape((9,9));
print t
Output:
[[2 0 0 0 0 0 0 4 8]
[0 0 0 0 7 5 0 9 0]
[0 6 0 0 3 0 1 0 0]
[0 0 0 3 0 0 0 0 0]
[3 0 0 0 1 0 0 0 8]
[0 0 0 0 0 9 0 0 0]
[0 0 1 0 8 0 0 9 0]
[0 2 0 7 3 0 0 0 0]
[5 7 0 0 0 0 0 0 4]]
should work, in python3 you might replace "(m/3)*3" with "int(m/3)*3"
[[board[(m/3)*3+i][(m%3)*3+j] for i in range(3) for j in range(3)] for m in range(9)]
this uses no builtins and is faster 3 nested for loops
def get_boxes(board):
boxes = []
for i in range(9):
if i == 0 or i % 3 == 0:
box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]
boxes.append(box_set_1)
box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
boxes.append(box_set_2)
box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
boxes.append(box_set_3)
def get_boxes(board):
boxes = []
for i in range(9):
if i == 0 or i % 3 == 0:
box_set_1 = board[i][:3] + board[i + 1][:3] + board[i + 2][:3]
boxes.append(box_set_1)
box_set_2 = board[i][3:6] + board[i + 1][3:6] + board[i + 2][3:6]
boxes.append(box_set_2)
box_set_3 = board[i][6:] + board[i + 1][6:] + board[i + 2][6:]
boxes.append(box_set_3)
return boxes

Categories