Use Python __repr__() for 2D List - python

Is there a way to make __repr__() return a 2d list so that it prints row by row in Python?
My attempt is below. I can't see how I can insert new lines, like in print("..", end="\n").
class Board:
def __init__(self, rows = 6, cols=7, fill=0):
self.rows = rows
self.cold = cols
self.symbol = fill
self.board = [[fill] * cols for row in range(rows)]
def __repr__(self):
return str([self.board[i] for i in range(len(self.board))])
board = Board()
print(board)

You really shouldn't be using __repr__() for this use – let's call it .format() instead, maybe?
Either way, you'll want to generate lines out of the characters with no separator (''.join(...)), then join those lines with '\n':
def format(self):
return '\n'.join([''.join(str(c) for c in row) for row in self.board])

Related

Printing out a matrix out of a two dimensional list

I would like to implement the str method to nicely format the string representation of the matrix: one line per row, two characters per number (%2d) and a space between numbers. For example:
m = Matrix([[1,0,0],[0,1,0],[0,0,1]])
print(m)
1 0 0
0 1 0
0 0 1
I've tried this:
class Matrix:
def __init__(self, rows):
self.rows = rows
def __str__(self):
for element in self.rows:
for i in element:
print(i, end=" ")
print()
But my output becomes
1 2 3
4 5 6
7 8 9
None
How would I solve this? Because the none shouldn't be there.
The __str__ method has to return a string, not print it.
What you are seeing is:
The prints inside of __str__.
The return value of __str__, which is None.
To correct it, build a string in __str__ and return it.
class Matrix:
def __init__(self, rows):
self.rows = rows
def read(self):
for element in self.rows:
for i in element:
print(i, end=" ")
print('\n')
m = Matrix([[1,0,0],[0,1,0],[0,0,1]])
m.read()
You Should use something like this. Creating a new function to represent your data is good practice than trying to use the __str__ method to do your job. because you might need to handle other edge cases explicitly
Output:
1 0 0
0 1 0
0 0 1
Note: This way you can remove None at the end as well
because The first is inside function and the second is outside function. When a function doesn't return anything, it implicitly returns None.
Maybe you could do it like this?
class Matrix:
def __init__(self, rows):
self.rows = np.array(rows)
def __str__(self):
return "\n".join(np.array2string(row)[1:-1] for row in self.rows)
m = Matrix([[1,0,0],[0,1,0],[0,0,1]])
print(m)
Notice that we here convert rows to to a 2d numpy array first. If you want to avoid numpy for some reason, you can do this.
class Matrix:
def __init__(self, rows):
self.rows = rows
def __str__(self):
return '\n'.join(' '.join(map(str, row)) for row in self.rows)
m = Matrix([[1,0,0],[0,1,0],[0,0,1]])
print(m)

Generate Vigenère Cypher table in Python

I've been struggling in creating the vigenere table in python
That should be the result:
So basically I have the entire alphabet on the first line, and the alphabet shifted by one letter on the second one etc.
That's my code so far:
class CypherTable:
def __init__(self):
self.matrix = [[chr(i) for i in range(ord('a'),ord('z')+1)] for i in range(5)]
def __str__(self):
for i in range(len(self.matrix)):
print self.matrix[i]
return ""
table = CypherTable()
print(table)
I managed to print letters from a to z a number of times but I don't know how to modify each interaction in order to shift the first letter by one.
I'm used to work in java where you first define the array length and then populate it, but since python has a faster syntax I can't figure out what's the best way to do it.
A simpler way is to use the string module:
from string import ascii_uppercase as l
class CypherTable:
def __init__(self):
self.final_table = [l[i:]+l[:i] for i in range(len(l))]
for i in CypherTable().final_table:
print(i)
Output:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
BCDEFGHIJKLMNOPQRSTUVWXYZA
CDEFGHIJKLMNOPQRSTUVWXYZAB
DEFGHIJKLMNOPQRSTUVWXYZABC
EFGHIJKLMNOPQRSTUVWXYZABCD
FGHIJKLMNOPQRSTUVWXYZABCDE
GHIJKLMNOPQRSTUVWXYZABCDEF
HIJKLMNOPQRSTUVWXYZABCDEFG
IJKLMNOPQRSTUVWXYZABCDEFGH
JKLMNOPQRSTUVWXYZABCDEFGHI
KLMNOPQRSTUVWXYZABCDEFGHIJ
LMNOPQRSTUVWXYZABCDEFGHIJK
MNOPQRSTUVWXYZABCDEFGHIJKL
NOPQRSTUVWXYZABCDEFGHIJKLM
OPQRSTUVWXYZABCDEFGHIJKLMN
PQRSTUVWXYZABCDEFGHIJKLMNO
QRSTUVWXYZABCDEFGHIJKLMNOP
RSTUVWXYZABCDEFGHIJKLMNOPQ
STUVWXYZABCDEFGHIJKLMNOPQR
TUVWXYZABCDEFGHIJKLMNOPQRS
UVWXYZABCDEFGHIJKLMNOPQRST
VWXYZABCDEFGHIJKLMNOPQRSTU
WXYZABCDEFGHIJKLMNOPQRSTUV
XYZABCDEFGHIJKLMNOPQRSTUVW
YZABCDEFGHIJKLMNOPQRSTUVWX
ZABCDEFGHIJKLMNOPQRSTUVWXY
To be even cleaner, particularly if you will not be declaring any other methods in the class, you can use #classmethod:
from string import ascii_uppercase as l
class CypherTable:
final_table = [l[i:]+l[:i] for i in range(len(l))]
#classmethod
def show_board(cls):
for i in cls.final_table:
print(i)
CypherTable.show_board()
Regarding your recent comment, you can try this:
from string import ascii_uppercase as l
class CypherTable:
def __init__(self):
self.final_table = [l[i:]+l[:i] for i in range(len(l))]
def cross(self, b, a):
val1 = self.final_table[0].index(a)
new_letter = [i for i in self.final_table if i[0] == b][0][val1]
return new_letter
c = CypherTable()
print(c.cross('P', 'C'))
Output:
'R'
Here's your code with a minimum amount of changes. You can use modulo to loop from 26 back to 0. Note that __str__ should return a string and shouldn't print anything:
class CypherTable:
def __init__(self):
self.matrix = [[chr(ord('A') + (i + j) % 26) for i in range(26)] for j in range(5)]
def __str__(self):
return "\n".join('|'.join(row) for row in self.matrix)
table = CypherTable()
print(table)
It outputs:
A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A
C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B
D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C
E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|A|B|C|D

How to properly create a list subclass that returns a list generated from file in python?

I am running into some problems with subclassing.
I need to create a class that inherits list properties but I need the returned list (self.tiles_pool) to be one that is created when the class is constructed. The list is generated by an external CSV file. I tried creating the class without inheritance but quickly realized there was no way to return my list without creating a separate method to do so. But I need the instance of the class to be a list object (i.e. print the generated list when I print the object). The class is for creating a Tile Pool like the bag of letter tiles in scrabble.
If there is some way of returning my list (self.tiles_pool) without inheritance and without using user defined methods that would be better.
Here is my code so far:
import csv
import random
class TilePool(list):
def __init__(self):
list.__init__(self)
# Open csv file
with open("tiles.csv") as f:
# Read csv into list of lists of each lines values
tiles_csv = csv.reader(f, delimiter=",")
# Convert the list into a tile pool
self.tiles_pool = [(line[0], line[1])
for line in tiles_csv if len(line[0]) == 1
for x in xrange(int(line[2]))]
del tiles_csv
def pop(self, tile_count=None):
assert len(self.tiles_pool) > 0, "# Tile Pool is empty"
if tile_count is None:
tile_count = 7
assert tile_count in xrange(1, 8), "# Tile Count must be between 1 and 7"
new_tiles = []
counter = 1
while len(self.tiles_pool) > 0 and counter <= tile_count:
rand_choice = random.choice(self.tiles_pool) # Get a random tile
new_tiles.append(rand_choice) # Add it to new_tiles list
self.tiles_pool.remove(rand_choice) # Delete it from pool
counter += 1
return new_tiles
def view_pool(self):
if len(self.tiles_pool) == 0:
print("# Tile Pool is empty")
else:
for tile in self.tiles_pool:
print("{letter}: {score}".format(letter=tile[0], score=tile[1]))
print len(self.tiles_pool)
I understand that this implementation may seem strange and I could probably just put this in a function but I am under instruction to make it a class. Any help or advice would be much appreciated. Thanks.
Why subclass list if you don't use it? self is the list you want, there is no need to create a tiles_pool. Since lists can be initialized with a sequence, delay parent __init__ until you can feed it the csv. Your code does some things I don't understand such as duplicating tiles line[2] times, but I figure you know what you are doing there.
In this sample, I remove tiles_pool in favor of using self and do a few other tweaks like using the "truthiness" of lists (bool([1]) is True while bool([]) is False) instead of using len but it should work the same as the original.
import csv
import random
class TilePool(list):
def __init__(self):
with open("tiles.csv") as f:
tiles_csv = csv.reader(f, delimiter=",")
list.__init__(self, (line[0:2]
for line in tiles_csv if len(line[0]) == 1
for x in xrange(int(line[2]))))
def pop(self, tile_count=None):
# non-empty list is truthy
assert self, "# Tile Pool is empty"
if tile_count is None:
tile_count = 7
assert tile_count in range(1, 8), "# Tile Count must be between 1 and 7"
new_tiles = []
counter = 1
while self and counter <= tile_count:
rand_choice = random.choice(self) # Get a random tile
new_tiles.append(rand_choice) # Add it to new_tiles list
self.remove(rand_choice) # Delete it from pool
counter += 1
return new_tiles
def view_pool(self):
if not self:
print("# Tile Pool is empty")
else:
for tile in self:
print("{letter}: {score}".format(letter=tile[0], score=tile[1]))
print len(self)
t = TilePool()
t.pop(3)
t.view_pool()
If you want to avoid inheritance and user-defined methods, I'd leverage python's magic methods to do so.

Why do I always get the error "list" object has no attribute 'tranpose'?

This is my code:
class Matrix(object):
"""List of lists, where the lists are the rows of the matrix"""
def __init__ (self, m=3,n=3,ma=[[1,2,3],[4,5,6], [7,8,9]]):
self.n_rows=m
self.n_cols=n
self.matrix=ma=list(ma)
def __repr__(self):
"""String representation of a Matrix"""
output= "Matrix: \n{} \n Your matrix has \n {} columns \n {} rows"\
.format(self.matrix, self.n_cols, self.n_rows)
return output
def transpose (self):
"""Transpose the Matrix: Make rows into columns and columns into rows"""
ma_transpose=[]
for r in zip(*self.matrix):
ma_transpose.append(list(r))
return ma_transpose
def matrixmult (self,other):
"""Matrix Multiplication of 2 Matrices"""
m2=other.matrix
ma2_t=m2.transpose()
table=[]
for r in self.matrix:
row=[]
for n in ma2_t:
row.append(dot_mult(r,n))
table.append(row) into a list of row
res=table
return res
but each time I try to use the matrixmult function, i always get "the list object has no attribute matrixmult". Why is that? I have defined it earlier in the code no?
ma2_t=m2.transpose()
AttributeError: 'list' object has no attribute 'transpose'
Someone please help?
Last line of matrixmult() is returning a list. It should return a Matrix object:
return Matrix(self.n_rows, other.n_cols, res)
Also in the transpose method, you should have:
return Matrix(self.n_cols, self.n_rows, ma_transpose)

Create python 2d array indexed by string

(I'm not too great at python, so forgive me if this is a stupid question)
So I want to create a data structure that represents this -
word1 word2
word3 1 2
word4 3 4
Right now I've tried doing something like this -
self.table = [][]
but this is giving me an invalid syntax error(I guess because I haven't initialized the arrays?). However, even if I were to use this I wouldn't be able to use it because I don't know how large my x and y dimension is(it seems like there would be an array out of index exception).
Should I be using a double dictionary? What should I be using?
Maybe you can try initializing your table with
self.table = {r : { c : 0 for c in ['word1', 'word2']} for r in ['word3', 'word4']}
and then you can access each position by
self.table['word3']['word1'] = 2
Python doesn't have a ready-made instruction to create a bi-dimensional matrix, but it's easy to do that using list comprehensions:
matrix = [[0] * cols for i in range(rows)]
then you can access the matrix with, for example
matrix[row][col] += 42
assuming rows=10 and cols=20 then the row index must go from 0 to 9 and the col index from 0 to 19. You can also use negative indexes to mean counting from the end; for example
matrix[-1][-1] = 99
will set the last cell to 99
If you are not opposed to using an external library, you might check out
Pandas Data Frames
The idea is to create a dictionary, which maps the strings to the indeces. In the following there's a little class which overloads the '[ ]'-operator:
class ArrayStrIdx:
""" 2D Array with string as Indeces
Usage Example::
AA = ArrayStrIdx()
AA["word1", "word3"] = 99
print(AA["word2", "word5"])
"""
cols ="word1 word2"
rows ="word3 word4 word5"
dd = [[10,11,12],[20,21,22]] # data
def __init__(self):
""" Constructor builds dicts for indexes"""
self.ri = dict([(w,i) for i,w in enumerate(self.rows.split())])
self.ci = dict([(w,i) for i,w in enumerate(self.cols.split())])
def _parsekey(self, key):
""" Convert index key to indeces for ``self.dd`` """
w0, w1 = key[0], key[1]
return self.ci[w0], self.ri[w1]
def __getitem__(self, key):
""" overload [] operator - get() method"""
i0, i1 = self._parsekey(key)
return self.dd[i0][i1]
def __setitem__(self, key, value):
""" overload [] operator - set() method """
i0, i1 = self._parsekey(key)
self.dd[i0][i1] = value
Update: Expanded answer to allow something like AA["word1", "word3"] = 23.

Categories