Random double loop in Python - python

I would like to create a random double loop in Python.
For example, for (N,N)=(2,2) the program should give:
0 1
0 0
1 1
1 0
Or another example
0 0
1 1
1 0
0 1
So far, I have done this:
r1 = list(range(2))
r2 = list(range(2))
random.shuffle(r1)
random.shuffle(r2)
for i in r1:
for j in r2:
# Do something with i
This, however, does not give the desired result, because I want i's to be shuffled too and not give for example all (1,x) sequentially. Any ideas?

Shuffle the product of the ranges, not each individual range.
import itertools
pairs = list(itertools.product(r1, r2)) # [(i,j) for i in r1 for j in r2]
random.shuffle(pairs)
for i, j in pairs:
...

Related

Creating matrix with for loop in python

I have a list with 4 elements. Each element is a correct score that I am pulling from a form. For example:
scoreFixed_1 = 1
scoreFixed_2 = 2
scoreFixed_3 = 3
scoreFixed_4 = 4
scoreFixed = [scoreFixed_1, scoreFixed_2, scoreFixed_3, scoreFixed_4]
Then, I need to add:
scoreFixed_1 to fixture[0][0]
scoreFixed_2 to fixture[0][1]
scoreFixed_3 to fixture[1][0]
scoreFixed_4 to fixture[1][1]
Hence, I need to create a triple for loop that outputs the following sequence so I can index to achieve the result above:
0 0 0
1 0 1
2 1 0
3 1 1
I have tried to use this to create this matrix, however I am only able to get the first column correct. Can anyone help?
for x in range(1):
for y in range(1):
for z in range(4):
print(z, x, y)
which outputs:
0 0 0
1 0 0
2 0 0
3 0 0
Your logic does not generate the table, you want something like:
rownum = 0
for x in range(2):
for y in range(2):
print (rownum, x, y)
rownum += 1
(Edit: The question has been changed, to accomplish the new desire, you want something like this:)
scoreIndex = 0
for x in range(2):
for y in range(2):
fixture[x][y] += scoreFixed[scoreIndex]
scoreIndex += 1
After your edit, it seems like we can split the 'sequence' into:
First column, regular ascending variable ( n += 1)
Second and third column, binary counter (00, 01, 10, 11)
0 0 0
1 0 1
2 1 0
3 1 1
^ ^------- These seem like a binary counter
(00, 01, 10, 11)
^------ A regular ascending variable
( n += 1 )
Using that 'logic' we can create a code that looks like
import itertools
scoreFixed = 0
for i in itertools.product([0,1],repeat=2):
print(scoreFixed, ' '.join(map(str,i)))
scoreFixed += 1
And wil output:
0 0 0
1 0 1
2 1 0
3 1 1
As you can test in this online demo
for x in range(4):
z = int(bin(x)[-1])
y = bin(x)[-2]
y = int(y) if y.isdigit() else 0
print(x, y, z)

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

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]]

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