I'm fairly new to python and I am having trouble with an array.
I'm having a problem with a symmetric matrix. Being symmetric, X[0][6] is the same as X[6][0]. I'm looking to be able to append all non-zero values in said array into a list - however I don't want to include elements on the diagonal nor duplicates of elements on one of the sides of the diagonal. For example, I only want to append X[0][6] but not also X[6][0].
The 2D array is as follows:
X = [[9, 0, 0, 1, 0, 0, 6, 0],
[0, 4, 0, 0, 0, 0, 0, 1],
[0, 0, 9, 0, 4, 0, 0, 0],
[1, 0, 0, 3, 0, 0, 0, 1],
[0, 0, 4, 0, 8, 0, 0, 3],
[0, 0, 0, 0, 0, 4, 0, 0],
[6, 0, 0, 0, 0, 0, 9, 2],
[0, 1, 0, 1, 3, 0, 2, 8]]
I've attempted a for loop like so:
non_zero_entries = []
for i in X:
for j in i:
if j > 0:
non_zero_entries.append(j)
When I do this however, due to the nature of the symmetry of the array I get the following output which has not only the diagonal but also the duplicates within the matrix:
Out: [9, 1, 6, 4, 1, 9, 4, 1, 3, 1, 4, 8, 3, 4, 6, 9, 2, 1, 1, 3, 2, 8]
Ideally I need to be able to transform my matrix to look like this so that the diagonal and the other side of becomes 0.
ideal_X = [[0, 0, 0, 1, 0, 0, 6, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 4, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 3],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 2],
[0, 0, 0, 0, 0, 0, 0, 0]]
This would give the output that I require:
Out: [1, 6, 1, 4, 1, 3, 2]
How would I either transform my matrix into the one I've provided, or is there a simpler way to get my desired output with the initial matrix?
You have the right idea in writing two nested for loops to iterate through the elements of your matrix. The outer for loop iterates once through each row of the matrix, which is already correct; you just need to change the inner for loop so that instead of iterating over every element in the row, it only iterates through the elements on one side of the diagonal.
If you don't care which "side" of the diagonal (upper or lower) you extract the non-zero elements from, it's easiest to get them from the lower side of the diagonal, by doing this:
for row_num in range(len(X)):
for col_num in range(row_num):
if X[row_num][col_num] > 0:
non_zero_entries.append(X[row_num][col_num])
Note that instead of using a "for-each" loop, where the loop variable is each entire row, we use a for loop with a range, where the loop variable is a number. This has equivalent behavior (X[row_num] is the same as i in your original code), but allows us to have a variable that counts which row the loop is currently on. This number, row_num, is equal to the index within the row (the column number) that is the "diagonal" entry. Thus the inner for loop can use a range that ends at row_num, rather than len(X[row_num]), to only iterate over the entries from 0 to the "diagonal" entry.
If you specifically want the entries from the upper side of the diagonal, the inner for loop's range needs to be a little more complicated:
for row_num in range(len(X)):
for col_num in range(row_num+1, len(X[row_num])):
if X[row_num][col_num] > 0:
non_zero_entries.append(X[row_num][col_num])
In this code, range(row_num+1, len(X[row_num])) produces a range for the inner for loop that starts at the entry after the "diagonal" entry, and ends at the end of the row.
Related
I have the written the code below, it's not ready yet but I ran into problems when testing it. The goal is to check whether or not numbers 1 to 9 appear more than once in one single row:
def rivi_oikein(sudoku: list, rivi_nro: int):
unique_list = [] #4
row = sudoku[rivi_nro]
zeros = row.count(0) #6
others = len(unique_list)
for i in row:
if i not in unique_list:
unique_list.append(i)
print(unique_list) # prints -> [9, 0, 8, 3]
print(row) # prints -> [9, 0, 0, 0, 8, 0, 3, 0, 0]
print(others) # prints -> 0
print(zeros) # prints -> 6
if __name__ == "__main__":
sudoku = [
[9, 0, 0, 0, 8, 0, 3, 0, 0],
[2, 0, 0, 2, 5, 0, 7, 0, 0],
[0, 2, 0, 3, 0, 0, 0, 0, 4],
[2, 9, 4, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 7, 3, 0, 5, 6, 0],
[7, 0, 5, 0, 6, 0, 4, 0, 0],
[0, 0, 7, 8, 0, 3, 9, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 3],
[3, 0, 0, 0, 0, 0, 0, 0, 2]
]
print(rivi_oikein(sudoku, 0))
enter code here
What confuses me is the "print(others) as it's supposed to be "len(unique_list)" which contains 4 numbers. Why the len() isn't working?
Sorry for the bad indent. I can't figure out how to copy+paste it correctly.
When you run others = len(unique_list), the length of unique_list really is 0. This syntax doesn't forever bind the variable others to the length of unique_list; it just grabs whatever that length is at the moment of running that instruction, and stores it (as a number, completely independent from unique_list henceforth) within others, so that's what you're seeing.
You could, for instance, print(len(unique_list)) instead if what you want is to find the length of it at the time of printing; or, if you do want to store it as well, assign that value when it makes sense (i.e, when the list is at the state you wish to sample):
others = len(unique_list)
print(others)
or some such thing.
So say I've got a 2D array like:
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 2],
[0, 2, 2, 0, 2],
[1, 1, 2, 1, 1],
]
And I want the two players (player 1 is represented by 1 and player 2 is represented by 2) to be able to place counters down the columns (like connect 4). How can I find the next available row (if there are any)?
I can parse the column number
Thanks!
table = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 2],
[0, 2, 2, 0, 2],
[1, 1, 2, 1, 1],
]
def move(col, player, table):
available_rows = [i for i in range(len(table)) if table[i][col]==0]
if available_rows == []:
return False # i.e. you can not place on column col. invalid move
target_row = available_rows[-1] # target_row is the next available move on column col
table[target_row][col] = player
return True # i.e. valid move
print(table)
move(0, 2, table) # player 2 has placed its move on column 0 (zero based index)
print(table)
Output
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 2],
[0, 2, 2, 0, 2],
[1, 1, 2, 1, 1]
]
[[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 2],
[1, 2, 2, 0, 2],
[1, 1, 2, 1, 1]]
You have to check whether the output of move is true or not, to make sure the move is valid.
You can use a for loop to loop through the array, and check if the current row has any zero in it.
for row in array:
if row.count(0) > 0:
# this row has available slots
# Do something here
break
else:
# No free slot at all for all rows
# Do something here
I think I've found a solution:
def findNextRow(self, rowNumber):
for rowIndex in range(len(self._grid), 0, -1):
if self._grid[rowNumber][rowIndex] == 0:
return rowIndex-1
return False
You loop backwards through the 2d array. If the column number you parsed through and the current row is 0, then return the index-1 (since python array indexing starts at 0). If no row can be found, the loop will end without returning anything so you can return False.
I have been trying to get inside a list of sublist just to get one value out but cannot seem to get it working any ideas. Below is the list of sublist and for example I want to print just the first number of the first list out. Hope that makes sense. I have tried looking at other sources but none got exactly what I was after.
[[0, 0, 0, 3, 0, 4, 0, 3], [0, 0, 0, 0, 0, 3, 0, 7], [0, 0, 1, 0, 0, 5, 0, 4], [0, 0, 0, 1, 3, 1, 0, 5], [1, 1, 1, 0, 0, 0, 2, 5], [0, 0, 0, 1, 1, 5, 0, 3], [0, 0, 0, 5, 3, 0, 0, 2]]
To acces an item inside a list of lists, you fist select the list you want to access and then the item you want to access:
the first list is at index 0 and the first item is at index 0 of that:
list_of_lists = [[0,1,2,3],[10,11,12,13]]
first_of_first = list_of_lists[0][0]
for the third item of the second list it would be:
third_of_second = list_of_lists[1][2]
Note that python is 0 indexed, so the indexes always turn out one lower than the "Nth" item so the second item is at index 1.
Also note that when you say "the third item of the second list" that the order in which you access it is in reverse, i.e. list_of_lists[1][2]
I have a list of lists and I want to create multiple smaller lists from specific indexes in this list. If I have this big "matrix" can I create a small list made up of integers collected from this matrix?
Code:
matrix = [
[0, 0, 0, 5, 0, 0, 0, 0, 6],
[8, 0, 0, 0, 4, 7, 5, 0, 3],
[0, 5, 0, 0, 0, 3, 0, 0, 0],
[0, 7, 0, 8, 0, 0, 0, 0, 9],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[9, 0, 0, 0, 0, 4, 0, 2, 0],
[0, 0, 0, 9, 0, 0, 0, 1, 0],
[7, 0, 8, 3, 2, 0, 0, 0, 5],
[3, 0, 0, 0, 0, 8, 0, 0, 0],
]
list1 = ([index 1, row 1], [index 2, row 2])
list2 = ([index 3, row 6], [index 7, row 9])
etc.
How would I do this correctly in Python. Help me fill in what would actually go in the parenthesis.
Thanks!
if index1 means FIRST index, row1 means FIRST row,
then matrix[0][0] = 0 in this case.
matrix[1][0] = 8
matrix[1][5] = 7
In all, you can do matrix[row_index][col_index]
So
list1 = [ matrix[0,0], matrix[2][2] ]
Hope this helps.
list1 = [matrix[1][1], matrix[2][2]]
list2 = [matrix[6][3], matrix[9][7]]
etc...
You basically have a list of lists here. You call items in a list by:
listname[index]
SO....
matrix[0] will give you [0, 0, 0, 5, 0, 0, 0, 0, 6]
matrix[0][0] will give you 0.... that is, the zero-th element of the zero-th list.
Remember, the "first" element of any list is really the zero-th element. So matrix[1] will give you the "second" thing in your list.
list1 = [matrix[1][1], matrix[2][2]]
list2 = [matrix[6][3], matrix[9][7]]
Also a note to help you ask better questions... the examples you gave call for lists but your examples are items grouped by parentheses which denote tuples. Lists are denoted by square brackets. []
something like this:
newmatrix = []
for n,i in enumerate(matrix[0]):# assuming the lists are in the same length
templist =[]
for l in matrix:
templist.append(l[n])
print "templist: ",n,"content: ",templist
newmatrix.append(templist)
edit: just realized that I completly misread the question. not relevant answer, sorry. not deleting because maybe this could be relevant for someone else
I am trying to select specific column elements for each row of a numpy array. For example, in the following example:
In [1]: a = np.random.random((3,2))
Out[1]:
array([[ 0.75670668, 0.1283942 ],
[ 0.51326555, 0.59378083],
[ 0.03219789, 0.53612603]])
I would like to select the first element of the first row, the second element of the second row, and the first element of the third row. So I tried to do the following:
In [2]: b = np.array([0,1,0])
In [3]: a[:,b]
But this produces the following output:
Out[3]:
array([[ 0.75670668, 0.1283942 , 0.75670668],
[ 0.51326555, 0.59378083, 0.51326555],
[ 0.03219789, 0.53612603, 0.03219789]])
which clearly is not what I am looking for. Is there an easy way to do what I would like to do without using loops?
You can use:
a[np.arange(3), (0,1,0)]
in your example above.
OK, just to clarify here, lets do a simple example
A=diag(arange(0,10,1))
gives
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 3, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 4, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 5, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 6, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 7, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 8, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 9]])
then
A[0][0:4]
gives
array([0, 0, 0, 0])
that is first row, elements 0 to 3. But
A[0:4][1]
doesn't give the first 4 rows, the 2nd element in each. Instead we get
array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
i.e the entire 2nd column.
A[0:4,1]
gives
array([0, 1, 0, 0])
I'm sure there is a very good reason for this and which makes perfect sense to programmers
but for those of us uninitiated in that great religion it can be quite confusing.
This isn't an answer so much as an attempt to document this a bit. For the answer above, we would have:
>>> import numpy as np
>>> A = np.array(range(6))
>>> A
array([0, 1, 2, 3, 4, 5])
>>> A.shape = (3,2)
>>> A
array([[0, 1],
[2, 3],
[4, 5]])
>>> A[(0,1,2),(0,1,0)]
array([0, 3, 4])
Specifying a list (or tuple) of individual row and column coordinates allows fancy indexing of the array. The first example in the comment looks similar at first, but the indices are slices. They don't extend over the whole range, and the shape of the array that is returned is different:
>>> A[0:2,0:2]
array([[0, 1],
[2, 3]])
For the second example in the comment
>>> A[[0,1],[0,1]]
array([0, 3])
So it seems that slices are different, but except for that, regardless of how indices are constructed, you can specify a tuple or list of (x-values, y-values), and recover those specific elements from the array.