This question already has answers here:
Block tridiagonal matrix python
(9 answers)
Closed 5 years ago.
How can I create this matrix using python ?
I've already created S , T , X ,W ,Y and Z as well as the first and the last line of L.
Something like this (it's a draft!). Make a class that stores 3 lists (diagonal, upper diagonal and lower diagonal) and expose a way of editing those values.
class TBMatrix:
def __init__(self,size):
self._size = size #Has to be square I guess?
self._diagonal = [None for i in range(0,size)]
self._upper_diagonal = [None for i in range(0,size - 2)]
self._lower_diagonal = [None for i in range(0,size - 2)]
def get(self,row,col):
if row == col:
return self._diagonal[row]
if row == col - 1:
return self._lower_diagonal[col]
if row == col + 1:
return self._upper_diagonal[row]
return 0 #or None, if you want a matrix that contains objects
def set(self,row,col,value):
if row == col:
self._diagonal[row] = value
elif row == col - 1:
self._lower_diagonal[col] = value
elif row == col + 1:
self._upper_diagonal[row] = value
else:
#No effect, maybe you want to throw an exception?
pass
This is a quick draft, you'll need to do a bunch of checks to make sure there is no trying to assign an index outside of the list sizes. But this should get you started.
Another alternative is to override the __getitem__ and __setitem__ to return a row full of 0's or None except where it need to hold a spot for self._diagonal, self._upper_diagonal and self._lower_diagonal. But it just seems more complicated.
Related
So I wrote a function slanted(grid) which takes in a grid and returns the combination of letters horizontally.
For instance, if grid is
['q','q','d'],
['s','d','e'],
['e','g','h']
then slanted(grid) should return
['d','qe','qdh','sg','e']
I tried to do this by writing up this code for slanted(grid)
def slanted(grid):
results = []
for j in range(len(grid)-1):
tmp = ""
for i in range(len(grid)):
tmp += [j+i][i]
results.append(tmp)
return results
print(slanted([['q','q','d'],['s','d','e'],['e','g','h']]))
but I'm getting an error message saying:
TypeError: can only concatenate str (not "int") to str
what changes to my code should I make to get the right output as indicated above?
[j + i][i] creates a singleton list with one integer, and then attempts to access that integer. You should try to access an element of grid, e.g. by doing grid[j + i][i], but this causes an IndexError.
Here is my approach to your task. You can think of this as reading a series of diagonals, each starting from a different start row / column index. For each start index, we extract that given diagonal:
def extract_diagonal(grid, start_row, start_col):
row = start_row
col = start_col
letters = []
while row < len(grid) and col < len(grid[0]):
letters.append(grid[row][col])
row += 1
col += 1
return ''.join(letters)
def slanted(grid):
results = []
for col in range(len(grid) - 1, -1, -1):
results.append(extract_diagonal(grid, 0, col))
for row in range(1, len(grid)):
results.append(diagonal(grid, row, 0))
return results
# Prints ['d','qe','qdh','sg','e'].
print(slanted([['q','q','d'],['s','d','e'],['e','g','h']]))
Note that we're using ''.join() rather than repeated string concatenation here, as the former has a better time complexity. For more discussion on this, see this answer.
def calcScore(p):
if p[0] > p[1]:
x = 3
y = 0
elif p[0] == p[1]:
x = 1
y = 1
else:
x = 0
y = 3
return x,y
How would I apply this function to the first row of my dataframe?
I know how to apply it to the whole dataframe but can't seem to apply it to the first row only? Below is what I did with the whole dataframe. I am new to python so please forgive silly or stupid mistakes. Thank you. :)
result =(prem[['FTHG','FTAG']].apply(calcScore, axis = 1))
print(result)
apply is for applying a function to all rows or columns. If you just want one you can just do:
result = calcScore(perm.iloc[0, ['FHG', 'FtAG']])
so I've got a list of questions as a dictionary, e.g
{"Question1": 3, "Question2": 5 ... }
That means the "Question1" has 3 points, the second one has 5, etc.
I'm trying to create all subset of question that have between a certain number of questions and points.
I've tried something like
questions = {"Q1":1, "Q2":2, "Q3": 1, "Q4" : 3, "Q5" : 1, "Q6" : 2}
u = 3 #
v = 5 # between u and v questions
x = 5 #
y = 10 #between x and y points
solution = []
n = 0
def main(n_):
global n
n = n_
global solution
solution = []
finalSolution = []
for x in questions.keys():
solution.append("_")
finalSolution.extend(Backtracking(0))
return finalSolution
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
return finalSolution
def reject(k):
if solution[k] in solution: #if the question already exists
return True
if k > v: #too many questions
return True
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for x in solution:
if x in questions.keys():
points = points + questions[x]
if points in range (x, y+1) and k in range (u, v+1):
return True
return False
print(main(len(questions.keys())))
but it's not trying all possibilities, only putting all the questions on the first index..
I have no idea what I'm doing wrong.
There are three problems with your code.
The first issue is that the first check in your reject function is always True. You can fix that in a variety of ways (you commented that you're now using solution.count(solution[k]) != 1).
The second issue is that your accept function uses the variable name x for what it intends to be two different things (a question from solution in the for loop and the global x that is the minimum number of points). That doesn't work, and you'll get a TypeError when trying to pass it to range. A simple fix is to rename the loop variable (I suggest q since it's a key into questions). Checking if a value is in a range is also a bit awkward. It's usually much nicer to use chained comparisons: if x <= points <= y and u <= k <= v
The third issue is that you're not backtracking at all. The backtracking step needs to reset the global solution list to the same state it had before Backtracking was called. You can do this at the end of the function, just before you return, using solution[k] = "_" (you commented that you've added this line, but I think you put it in the wrong place).
Anyway, here's a fixed version of your functions:
def Backtracking(k):
finalSolution = []
for c in questions.keys():
solution[k] = c
print ("candidate: ", solution)
if not reject(k):
print ("not rejected: ", solution)
if accept(k):
finalSolution.append(list(solution))
else:
finalSolution.extend(Backtracking(k+1))
solution[k] = "_" # backtracking step here!
return finalSolution
def reject(k):
if solution.count(solution[k]) != 1: # fix this condition
return True
if k > v:
return True
points = 0
for q in solution:
if q in questions:
points = points + questions[q]
if points > y: #too many points
return True
return False
def accept(k):
points = 0
for q in solution: # change this loop variable (also done above, for symmetry)
if q in questions:
points = points + questions[q]
if x <= points <= y and u <= k <= v: # chained comparisons are much nicer than range
return True
return False
There are still things that could probably be improved in there. I think having solution be a fixed-size global list with dummy values is especially unpythonic (a dynamically growing list that you pass as an argument would be much more natural). I'd also suggest using sum to add up the points rather than using an explicit loop of your own.
I've been trying to solve this problem for a while. A M x N grid is given and we've to find number to paths from top left corner to bottom right corner.
Simple problem though; there are many solutions as well. Here're the details.
http://www.interviewbit.com/courses/programming/topics/math/problems/paths/
http://articles.leetcode.com/2010/11/unique-paths.html
I solved this problem in Java, and wrote one more solution in Python. Now I want to modify the previous solution with Memoized table so that the final answer gets collected at the bottom right cell. Value of a cell is the sum of its right and left adjacent cells.
Here's the code I can't debug:-
class Solution:
#Actual Recursive function
def paths(self,row,col):
if row == 0 or col == 0:
self.Mat[row][col] = 1
return 1
self.Mat[row][col-1] = self.paths(row, col-1)
self.Mat[row-1][col] = self.paths(row-1, col)
self.Mat[row][col] = self.Mat[row][col-1] + self.Mat[row-1][col]
return self.Mat[row][col]
# Driver Function. This will be called
def uniquePaths(self, A, B):
self.Mat = [[-1]*B]*A
ans = self.paths(A-1, B-1)
return self.Mat[A-1][B-1]
And here is my previous solution that works - But doesn't use memoized table.
class OldSolution:
def paths(self,row,col):
if row==0 or col==0:
return 1
elif row<0 or col<0:
return 0
elif row >0 and col > 0:
return self.paths(row-1,col) + self.paths(row,col-1)
def uniquePaths(self, A, B):
Mat = [ [-1] * B ] *A
return self.paths(A-1, B-1)
sol = OldSolution()
print sol.uniquePaths(3,3) # Prints 6
Test Cases:-
3, 3 = 6
15, 9 = 319770
The issue is with the initialization of the matrix. You essentially create the same row duplicated in every column so when you update a cell, all corresponding cells in all columns get updated.
Instead of:
self.Mat = [[-1]*B]*A
Use:
self.Mat = [[-1 for i in range(B)] for j in range(A)]
I'm trying to iterate through a matrix and check for the number of cells touching the current cell that have a value of 1. I'm getting an out of bounds exception and I'm not sure why.
for x in range(0,ROWS):
for y in range(0,COLS):
#get neighbors
neighbors = []
if x!=0 & y!=COLS:
neighbors.append([x-1,y+1])
if y!=COLS:
neighbors.append([x,y+1])
if x!=ROWS & y!=COLS:
neighbors.append([x+1,y+1])
if x!=0:
neighbors.append([x-1,y])
if x!=ROWS:
neighbors.append([x+1,y])
if x!=0 & y!=0:
neighbors.append([x-1,y-1])
if y!=0:
neighbors.append([x,y-1])
if x!=ROWS & y!=0:
neighbors.append([x+1,y-1])
#determine # of living neighbors
alive = []
for i in neighbors:
if matrix[i[0]][i[1]] == 1:
alive.append(i)
I'm getting the error
IndexError: list index out of range
at this line if matrix[i[0]][i[1]] == 1:
Why is this out of range and how should I fix it?
The problem is that you are using &. This is a bit-wise AND, not a logical AND. In Python, you just use and. For example:
if x!=0 and y!=COLS:
neighbors.append([x-1,y+1])
However the real reason why using the bit-wise AND causes a problem is order of operations - it has a higher precedence!
>>> 1 != 2 & 3 != 3
True
>>> (1 != 2) & (3 != 3)
False
>>> 1 != (2 & 3) != 3
True
So even though your logic looks right, order of operations means that your code's actual behavior is drastically different than what you were expecting.
The other issue with your code is that you are checking if x and y are equal to ROWS and COLS, rather than if they are equal to ROWS-1 and COLS-1, which are the true boundary conditions.
EDIT: I THINK I FOUND IT
Upon further inspection of your code, I found that you're using if x!=0 & y!=0. This is bit-wise AND not logical AND, so it's not going to give you the result you want. Use and instead of & and see if your problem goes away.
I would refactor this slightly to make it easier to read.
for loc_x in range(ROWS):
for loc_y in range(COLS): # btw shouldn't ROWS/COLS be flipped?
# if your matrix isn't square this could be why
x_values = [loc_x]
if loc_x < ROWS: x_values.append(loc_x+1)
if loc_x > 0: x_values.append(loc_x-1)
y_values = [loc_y]
if loc_y < COLS: y_values.append(loc_y+1)
if loc_y > 0: y_values.append(loc_y-1)
neighbors = [(x,y) for x in x_values for y in y_values if (x,y) != (loc_x,loc_y)]
alive = [matrix[n[0]][n[1]] for n in neighbors if matrix[n[0]][n[1]]==1]
Try running this with your code and see if it doesn't solve the issue. If not, you may need to test further. For instance, wrap the alive definition in try/except tags that will give a better traceback.
try:
alive = ...
except IndexError:
print("Location: {},{}\nneighbors: {}\nROWS:{}\nCOLS:{}".format(x_loc,y_loc, neighbors,ROWS,COLS))
raise
As an aside, I've solved this problem before by creating objects that held the linked information and going top-to-bottom left-to-right and having each check the field to its right and below it. E.g.:
class Field(object):
def __init__(self,x,y,value):
self.x = x
self.y = y
self.value = value
self.neighbors = neighbors
class Matrix(list):
def __init__(self,size):
self.ROWS,self.COLS = map(int,size.lower().split("x"))
for y in range(ROWS):
self.append([Field(x,y,random.randint(0,1)) for x in range(COLS)])
self.plot()
def plot(self):
for row in self:
for col in row:
try:
self[row][col].neighbors.append(self[row+1][col])
self[row+1][col].neighbors.append(self[row][col])
except IndexError: pass
try:
self[row][col].neighbors.append(self[row][col+1])
self[row][col+1].neighbors.append(self[row][col])
except IndexError: pass
Of course this doesn't take care of diagonals. I'm pretty sure you can figure out how to manage those, though!!