Related
So I am trying to create an NxN 2D array and then change its diagonal elemets to 1. Here is my code:
arr=[1,1,1,2,2,2]
table=[[0]*len(arr)]*len(arr)
for i in range(0,len(arr)):
table[i][i]=1
print(table)
However, whenever I run this code, I get this output:
[[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1]]
I am looking to get this:
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
I have been staring at my code for hours and I cannot figure out what's wrong
The interesting thing about this is that you are really only editing one list in the for loop, but there are just five pointers to that list. (In this case, the list would be [0, 0, 0, 0, 0, 0].) You can see this by printing the id of each list in table by using id():
>>> for t in table:
print(id(t))
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
Your numbers are likely different than mine, but they are all the same number, nevertheless. You also can see that the edits to one list are applied to the others in table by putting a print(table) statement after each index assignment statement.
So in order to 'fix' this, I would recommend using list comprehension instead. For example:
table = [[0]*len(arr) for _ in range(len(arr))]
If you checkout the ids of each list:
>>> for t in table:
print(id(t))
2236544617664
2236544616064
2236544616320
2236544615872
2236544618368
2236544622720
Since they are different, you can now use the method for changing only the diagonals:
>>> for i in range(0,len(arr)):
table[i][i]=1
>>> table
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
Your 2D "array" contains 6 lists which are the same list. Changes to any of those lists will also be reflected in the other lists. Consider this:
>>> l = [0] * 6
>>> x = [l]
>>> l[0] = 1
>>> l
[1, 0, 0, 0, 0, 0]
>>> x
[[1, 0, 0, 0, 0, 0]]
>>> x = [l, l, l]
>>> x
[[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]]
>>> x[-1][-1] = 100
>>> x
[[1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100]]
This is because the list x contains the list l, so any changes to l are also seen through the reference to the same list in x.
The problem is when multiplying mutable objects because it creates multiple references to the same mutable object.
You should initialise your table like this:
table = [[0 for j in range(len(arr))] for i in range(len(arr))]
or
table = [[0] * len(arr) for i in range(len(arr))]
which, despite the use of multiplication, works because each list is different.
You can create your table and populate it simultaneously in nested loops:
arr=[1,1,1,2,2,2]
table = []
for i in range(len(arr)):
table.append([0]*len(arr))
for j in range(len(arr)):
if i == j:
table[i][j] = 1
print(table)
#[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
Interesting.
Try to use numpy to avoid list trap:
import numpy as np
org_row = [0]*5
l = [org_row]*5
x = np.array(l, np.int32)
for i in range(len(x)):
x[i][i]=1
print(x)
output>:
output>
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]
I have two list. first list is a maze. It start 'O' and must be finished 'X'.
maze_list=[[0, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 1, 'O'],
[0, 0, 1, 0, 1, 0],
[0, 1, 1, 1, 1, 0],
['X', 1, 0, 1, 0, 0],
[0, 1, 0, 1, 1, 1]]
path_list=[[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
This part is finding start position.
column_size=len(maze_list)
row_size=len(maze_list[0])
def find_SF_position(X):
liste=[]
for i in range(column_size):
for j in range(column_size):
if maze_list[i][j]==X:
liste.append(i)
liste.append(j)
return liste
s_p=find_SF_position('O') #[1,5]
f_p=find_SF_position('X') #[4,0]
This part is main algorithm. x is for horizontal position. y is for vertical position
def solve_maze(maze,road,x,y):
global column_size
global row_size
road[y][x]=1
print(y,x)
#left
if x>0 and maze[y][x-1]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x-1,y)
#up
if y>0 and maze[y-1][x]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x,y-1)
#right
if x>row_size and maze[y][x+1]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x+1,y)
#down
if y>column_size and maze[y+1][x]==1 and road[y][x-1]==0:
return solve_maze(maze,road,x,y+1)
if maze[x][y]=='X':
return path_list
solve_maze(maze_list,path_list,s_p[1],s_p[0])
print(path_list)
I can't understand why it isn't working. It's start 'O'(maze_list[1,5]), it fill maze_list[1,4] then stop.
Finally path_list must be like this
path_list=[[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
You have a few problems in your code:
First your right and down conditions are reversed: x can never be greater than row_size. What you want to check is that x is not on the right border, meaning: x < row_size - 1. Same logic goes for the down case
Seems like you have a little copy-paste issue there: for example the road condition for up should be: road[y-1][x]==0. Same logic goes to all other cases.
Your condition to finding the end has a problematic logic: You check if the current cell is the 'X', but each step is only taken if there is 1 in the next cell, so how will you get to the 'X'? For example, after fixing above errors, the output I got was:
[0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 1]
[0, 0, 0, 0, 1, 0]
[0, 1, 1, 1, 1, 0]
[0, 1, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0]
As you can see, the 'X' was missed as the condition for down was taken at (4, 1) and a dead-end was reached
Lastly, what happens if you reach a dead-end? Your algorithm always takes the first step with conditions met, but what happens when you encounter an intersection? You need to check all possible paths. That's the point of recursion. The way you did it now doesn't add much over a loop.
I want to choose some elements from nested lists and use them inside 'for' loop.
I have taken elements needed from each nested list and created a new list. Then I used 'for' loop. However I wonder if there is more firct and faster option to do that.
list = [['name_1', 0, 0, 0], ['name_2', 0, 0, 0], ['name_3', 0, 0, 0]]
I have tried
new_list = [list[0][0], list[1][0], list[2][0]]
for element in new_list:
print(element)
Is it possible to create 'for' loop without creating a separate list for 'name' elements?
Just want to be more specific:
1. I don't want to create ANY new list a all. 2. If the code is:
new_list = [list[0][0], list[1][0], list[2][0]]
for element in new_list: #in this line I want 'element to be name_1, name_2 and name_3, so I want to loop over 'name' elements... print(element)
using list comprehension,
llist = [['name_1', 0, 0, 0], ['name_2', 0, 0, 0], ['name_3', 0, 0, 0]]
newlist = [x[0] for x in llist]
print(newlist) # ['name_1', 'name_2', 'name_3']
You can iterate the new_list and print the names as needed,
for name in newlist:
print(name)
If you don't want to create a new list for this purpose, you can do this,
llist = [['name_1', 0, 0, 0], ['name_2', 0, 0, 0], ['name_3', 0, 0, 0]]
for name in [x[0] for x in llist]:
print(name)
You can access the nested elements directly from the for loop:
inputlist = [['name_1', 0, 0, 0], ['name_2', 0, 0, 0], ['name_3', 0, 0, 0]]
for element in inputlist:
print(element[0])
Output:
name_1
name_2
name_3
How do I find if a sequence of numbers exists in a two-dimensional list? i.e.
matrix: [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0,
0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]]
if [1,1,1] in matrix:
print("It's in there")
else: print("It's not there")
I guess I could turn every int into a string but is there a slicker way?
Using an iterator over each cell of the matrix, I've managed to get a basic idea of what you wanted to achieve in Python script.
matrix = [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]]
matchCount = 0
lastNumber = None
for cell in matrix:
for number in cell:
if number == 1 and lastNumber == 1 or lastNumber == None:
matchCount += 1
if matchCount >= 3:
print("MATCH in cell " + str(cell))
lastNumber = number
matchCount = 0
lastNumber = None
What happens is, it steps into the cell. It it's the first iteration then allow entry into our iterator. We don't know if it's a match list yet, so push it back in our little list.
Stepping over and over, if we get enough matches in a row, then wonderful! Print we found a match in our matrix's cell!
I have to write a code for the N-queen chess board problem. I understand the theory behind it but dont understand how I should code it. In this exercise 0's represent spaces, and 1's represent queens)
so far I have only written:
import numpy as np
board=np.zeros((8,8))
board[0:,0]=1
Following this, I want to define what the rows in this board are and what the columns in this board are. So I am able to define collisions between the queens on the board.
Thank you.
I don't know how much I should be helping you (sounds like a homework), but my curiosity was piqued. So here's a preliminary exploration:
Representing a board as a 8x8 array of 0/1 is easy:
In [1783]: B=np.zeros((8,8),int)
But since a solution requires 1 queen per row, and only 1 per column, I can represent it as just a permutation of the column numbers. Looking online I found a solution, which I can enter as:
In [1784]: sol1=[2,5,1,6,0,3,7,4]
I can map that onto the board with:
In [1785]: B[np.arange(8),sol1]=1
In [1786]: B # easy display
Out[1786]:
array([[0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0]])
How about testing this? Row and column sums are easy with numpy. For a valid solution these must all be 1:
In [1787]: B.sum(axis=0)
Out[1787]: array([1, 1, 1, 1, 1, 1, 1, 1])
In [1788]: B.sum(axis=1)
Out[1788]: array([1, 1, 1, 1, 1, 1, 1, 1])
Diagonals differ in length, but can also be summed
In [1789]: np.diag(B,0)
Out[1789]: array([0, 0, 0, 0, 0, 0, 0, 0])
and to look at the other diagonals, 'flip' columns:
In [1790]: np.diag(B[:,::-1],1)
Out[1790]: array([0, 1, 0, 0, 0, 0, 0])
I can generate all diagonals with a list comprehension (not necessarily the fastest way, but easy to test):
In [1791]: [np.diag(B,i) for i in range(-7,8)]
Out[1791]:
[array([0]),
array([0, 0]),
array([0, 0, 0]),
array([1, 0, 0, 0]),
array([0, 0, 0, 0, 1]),
array([0, 0, 0, 1, 0, 0]),
array([0, 1, 0, 0, 0, 0, 0]),
array([0, 0, 0, 0, 0, 0, 0, 0]),
array([0, 0, 0, 0, 0, 0, 1]),
array([1, 0, 0, 0, 0, 0]),
array([0, 0, 0, 1, 0]),
array([0, 1, 0, 0]),
array([0, 0, 0]),
array([0, 0]),
array([0])]
and for the other direction, with sum:
In [1792]: [np.diag(B[:,::-1],i).sum() for i in range(-7,8)]
Out[1792]: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0]
No diagonal can have a sum >1, but some may be 0.
If the proposed solution is indeed a permutation of np.arange(8) then it is guaranteed to satisfy the row and column sum test. That just leaves the diagonal tests. The board mapping may be nice for display purposes, but it isn't required to represent the solution. And it might not be the best way to test the diagonals.
A brute force solution is to generate all permutations, and test each.
In [1796]: len(list(itertools.permutations(range(8))))
Out[1796]: 40320
There are, of course, smarter ways of generating and test solutions.
A few months ago I worked on a Sudoku puzzle question
Why is translated Sudoku solver slower than original?
the initial question was whether lists or arrays were a better representation. But I found, on an AI site, that an efficient, smart solver can be written with a dictionary.
There are quite a number of SO questions tagged Python and involving 8-queens. Fewer tagged with numpy as well.
==========
Your initial setup:
board[0:,0]=1
would pass the row sum test, fail the column sum test, and pass the diagonals tests.