I am writing a game of Connect 4 and have a Grid class that resembles the 2-dimensional grid that the game is played in. The underlying data structure of my Grid class is an instance variable self.grid - a 2-dimensional list.
I have overwritten the __iter__ method as such:
def __iter__(self):
for row in range(self.numRows):
for col in range(self.numCols):
yield self.grid[row][col]
which I can then call as:
for cell in grid:
# do something with yielded cell
At some points, I need to iterate over just a specified row or a specified column. Instead of writing
col = 0
for row in range(grid.numRows):
# do something with grid.grid[row][col]
is there any Pythonic, readable way to define a 2nd and 3rd __iter__ method along the lines of:
def __iter__(self, col)
for row in range(self.numRows):
yeild self.grid[row][col]
which would be called as:
for row in grid(col=0):
# do something with the yielded cell
and then the same, but with a specified row?
You can certainly have as many of these methods as you like. You just can't call them all __iter__(), because Python does not support method overloading. You could, for example, do this:
def rows(self, col):
for row in range(self.numRows):
yield self.grid[row][col]
def cols(self, row):
for col in range(self.numCols):
yield self.grid[row][col]
def cells(self):
for row in range(self.numRows):
for col in range(self.numCols):
yield self.grid[row][col]
You would then write something like
for row in grid.rows(col=0):
# Do something
Sure you can do that, no need to add special methods. Just add iterators, python 3 code below:
ALL = 0
ROW = 1
COL = 2
class db:
def __init__(self, n):
self.n = n
def __iter__(self):
return db_iter_all(self.n)
def __call__(self, what = ALL):
if what == ALL:
return db_iter_all(self.n)
if what == ROW:
return db_iter_row(self.n)
if what == COL:
return db_iter_col(self.n)
raise ValueError("What what?")
class db_iter_all:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 1
return r
class db_iter_row:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 3
return r
class db_iter_col:
def __init__(self, n):
self.i = 0
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.i > self.n:
raise StopIteration()
r = self.i
self.i += 5
return r
And simple example how to use it
grid = db(15)
for k in grid:
print(k)
for k in grid(ROW):
print(k)
for k in grid(COL):
print(k)
I need to implement an insert method (insert(self, index, val)), that inserts val before index, and a pop method (pop(self)), that removes the last element from mylist, onto the MyList class. The behavior should be identical to the methods already available in python.
Note: For the insert method, similarly with the append method already done, the capacity of the array should be doubled if there is no room for an additional element. The pop method should return the element removed from the list, and put None
in its place in the array. If pop was called on an empty list, an IndexError
exception should be raised.
My code thus far:
import ctypes # provides low-level arrays
def make_array(n):
return (n * ctypes.py_object)()
class MyList:
def __init__(self):
self.data = make_array(1)
self.capacity = 1
self.n = 0
def __len__(self):
return self.n
def append(self, val):
if(self.n == self.capacity):
self.resize(2 * self.capacity)
self.data[self.n] = val
self.n += 1
def resize(self, new_size):
new_array = make_array(new_size)
for ind in range(self.n):
new_array[ind] = self.data[ind]
self.data = new_array
self.capacity = new_size
def extend(self, other):
for elem in other:
self.append(elem)
def __getitem__(self, ind):
if not(0 <= ind <= self.n - 1):
raise IndexError('MyList index is out of range')
return self.data[ind]
def __setitem__(self, ind, val):
if not(0 <= ind <= self.n - 1):
raise IndexError('MyList index is out of range')
self.data[ind] = val
mylst1 = MyList()
for i in range(5):
mylst1.append(i)
import heapq
class PriorityQueue:
def __init__(self):
self.heap = []
def push(self, item, priority):
pair = (priority,item)
heapq.heappush(self.heap,pair)
def pop(self):
return heapq.heappop(self.heap)
def isEmpty(self):
return len(self.heap) == 0
def clear(self):
while not (self.isEmpty()):
self.heap.pop()
def getHeap(self):
return self.heap
def getLeng(self):
return len(self.heap)
def exists(self, item):
return len(list(set(self.heap) & set(item)))
pq = PriorityQueue()
x = "test"
pq.push(x,1)
print pq.exists(x)
it printed 0 when it should print 1 since intersection of a set with x and another set with x should be 1
am i overlooking things?
why is it printing 0 instead of 1?
You are pushing tuples of (priority,value) to the heap but want the exist method to work only on values, so you should get a value-only list/iterator out of your heap, something like this:
def exists(self, item):
return item in (x[1] for x in self.heap)
import random
import operator
import sys
import unittest
__version__ = "0.3"
class MatrixError(Exception):
""" An exception class for Matrix """
pass
class Matrix(object):
""" A simple Python matrix class with
basic operations and operator overloading """
def __init__(self, m, n, init=True):
if init:
self.rows = [[0]*n for x in range(m)]
else:
self.rows = []
self.m = m
self.n = n
def __getitem__(self, idx):
return self.rows[idx]
def __setitem__(self, idx, item):
self.rows[idx] = item
def __str__(self):
s='\n'.join([' '.join([str(item) for item in row]) for row in self.rows])
return s + '\n'
def __repr__(self):
s=str(self.rows)
rank = str(self.getRank())
rep="Matrix: \"%s\", rank: \"%s\"" % (s,rank)
return rep
def reset(self):
""" Reset the matrix data """
self.rows = [[] for x in range(self.m)]
def transpose(self):
""" Transpose the matrix. Changes the current matrix """
self.m, self.n = self.n, self.m
self.rows = [list(item) for item in zip(*self.rows)]
def getTranspose(self):
""" Return a transpose of the matrix without
modifying the matrix itself """
m, n = self.n, self.m
mat = Matrix(m, n)
mat.rows = [list(item) for item in zip(*self.rows)]
return mat
def getRank(self):
return (self.m, self.n)
def __eq__(self, mat):
""" Test equality """
return (mat.rows == self.rows)
def __add__(self, mat):
""" Add a matrix to this matrix and
return the new matrix. Doesn't modify
the current matrix """
if self.getRank() != mat.getRank():
raise MatrixError, "Trying to add matrixes of varying rank!"
ret = Matrix(self.m, self.n)
for x in range(self.m):
row = [sum(item) for item in zip(self.rows[x], mat[x])]
ret[x] = row
return ret
def __sub__(self, mat):
""" Subtract a matrix from this matrix and
return the new matrix. Doesn't modify
the current matrix """
if self.getRank() != mat.getRank():
raise MatrixError, "Trying to add matrixes of varying rank!"
ret = Matrix(self.m, self.n)
for x in range(self.m):
row = [item[0]-item[1] for item in zip(self.rows[x], mat[x])]
ret[x] = row
return ret
def __mul__(self, mat):
""" Multiple a matrix with this matrix and
return the new matrix. Doesn't modify
the current matrix """
matm, matn = mat.getRank()
if (self.n != matm):
raise MatrixError, "Matrices cannot be multipled!"
mat_t = mat.getTranspose()
mulmat = Matrix(self.m, matn) or Matrix(self.m, a)
for x in range(self.m):
for y in range(mat_t.m) or y==a:
mulmat[x][y] = sum([item[0]*item[1] for item in zip(self.rows[x], mat_t[y])])or a*x
return mulmat
def __iadd__(self, mat):
""" Add a matrix to this matrix.
This modifies the current matrix """
# Calls __add__
tempmat = self + mat
self.rows = tempmat.rows[:]
return self
def __isub__(self, mat):
""" Add a matrix to this matrix.
This modifies the current matrix """
# Calls __sub__
tempmat = self - mat
self.rows = tempmat.rows[:]
return self
def __imul__(self, mat):
""" Add a matrix to this matrix.
This modifies the current matrix """
# Possibly not a proper operation
# since this changes the current matrix
# rank as well...
# Calls __mul__
tempmat = self * mat
self.rows = tempmat.rows[:]
self.m, self.n = tempmat.getRank()
return self
def save(self, filename):
open(filename, 'w').write(str(self))
#classmethod
def _makeMatrix(cls, rows):
m = len(rows)
n = len(rows[0])
# Validity check
if any([len(row) != n for row in rows[1:]]):
raise MatrixError, "inconsistent row length"
mat = Matrix(m,n, init=False)
mat.rows = rows
return mat
#classmethod
def makeRandom(cls, m, n, low=0, high=10):
""" Make a random matrix with elements in range (low-high) """
obj = Matrix(m, n, init=False)
for x in range(m):
obj.rows.append([random.randrange(low, high) for i in range(obj.n)])
return obj
#classmethod
def makeZero(cls, m, n):
""" Make a zero-matrix of rank (mxn) """
rows = [[0]*n for x in range(m)]
return cls.fromList(rows)
#classmethod
def makeId(cls, m):
""" Make identity matrix of rank (mxm) """
rows = [[0]*m for x in range(m)]
idx = 0
for row in rows:
row[idx] = 1
idx += 1
return cls.fromList(rows)
#classmethod
def readStdin(cls):
""" Read a matrix from standard input """
print 'Enter matrix row by row. Type "q" to quit'
rows = []
while True:
line = sys.stdin.readline().strip()
if line=='q': break
row = [int(x) for x in line.split()]
rows.append(row)
return cls._makeMatrix(rows)
#classmethod
def readGrid(cls, fname):
""" Read a matrix from a file """
rows = []
for line in open(fname).readlines():
row = [int(x) for x in line.split()]
rows.append(row)
return cls._makeMatrix(rows)
#classmethod
def fromList(cls, listoflists):
""" Create a matrix by directly passing a list
of lists """
# E.g: Matrix.fromList([[1 2 3], [4,5,6], [7,8,9]])
rows = listoflists[:]
return cls._makeMatrix(rows)
I'm trying to put a scalar multiplication but it always fail.
For example,
a = [[2,2],[2,3]]
If I multiply it's like, 3*a = [[2,2],[2,3],[2,2],[2,3],[2,2],[2,3]]
How could I fix it?
For example, a = [[2,2],[2,3]] If I multiply it's like, 3*a = [[2,2],[2,3],[2,2],[2,3],[2,2],[2,3]]
Here, a is a list and not a Matrix. You can't overload the multiplication of a standard list by a scalar.
You can't multiply the whole list. The output you got is like a string multiplication.
a="hello"
b=a*3
print b
gives the output as
hellohellohello
That is what happens in your case. Multiply one by one
for i in range(len(a)):
for j in range(len(i)):
a[i][j]*=3
I am trying to create a class that will be able to make all possible calculations between matrix. the input is a matrix (doesn't matter the size), and on that matrix the class should do any calculations - either multiply, combine or substract. The different functions are as follow:
I need to have in this class:
__init__(self, data)
get_width(self)
get_height(self)
add(self, m)
scalar_multiply(self, a)
subtract(self, m)
multiply(self, m)
compare(self, m)
Thanks alot, it also needs to be with simple actions.
This is my code till now:
class Matrix:
def __init__(self, data):
self.data = data
def get_width(self):
return len(self.data[0])
def get_height(self):
return len(self.data)
def add(self, m):
lines = []
for j in range(len(self.data)):
line = []
for i in range(len(self.data[j])):
line.append(self.data[j][i] + m[j][i])
lines.append(line)
return lines
def scalar_multiply(self, a):
res = []
for j in range(len(self.data)):
line = []
for i in range(len(self.data)):
line.append(self.data[j][i]*a)
res.append(line)
return res
def subtract(self, m):
lines = []
for j in range(len(self.data)):
line = []
for i in range(len(self.data)):
line.append(self.data[j][i] - m[j][i])
lines.append(line)
return lines
def multiply(self, m):
lines = []
for j in range(len(self.data-1)):
line = []
for i in range(len(m[0])-1):
schum = 0
for k in range(len(self.data[0]-1)):
schum = self.data[j][k]*m[k][i]
line.append(schum)
lines.append(line)
return lines
def compare(self, m):
for j in range(len(self.data)):
for i in range(len(self.data)[j]):
while self.data[j][i] == m[j][i]:
return True
else:
return False
Do you need to create this yourself? If not, there is already an excellent implementation of this in numpy