How to implement a matrix with classes - python

I need to implement a matrix with N cells and these cells depend on K parameters, some fixed and other variables. I would like to do all this through the use of classes.
could someone explain to me the basic procedure?

I know, I should not answer this since it's a "homework", but I cannot resist a matrix class!!
Basically, a matrix is nothing more than a list of lists. Implementing it as a class means you should add some basic functionalities (methods) like, get the value of a specific row/column, print the matrix etc...
Here a simple one you can start with:
class Matrix2D:
def __init__(self):
'''
Init an empty matrix.
'''
self.matrix = []
self.rows = 0
self.columns = 0
self.name = 'Unnamed'
def __str__(self):
return self.matrix
def generate(self, rows, columns, verbose=False):
'''
Return a list of lists containing the indices of the matrix (row, col)
and prints it by row.
int, int -> [[(int, int), ...], ...]
'''
self.rows = rows
self.columns = columns
self.matrix = [[(row, col) for col in range(columns)] for row in range(rows)]
if verbose == True:
print(f'Generated a {self.rows} row/s by {self.columns} column/s matrix')
print('--------' * columns)
self.printme()
print('--------' * columns)
return self.matrix
def printme(self, verbose=False):
'''
Print the matrix by row.
'''
if verbose == True:
print(f'I am a {self.rows} row/s by {self.columns} column/s matrix')
for row in self.matrix:
print(row)
def get_row(self, n, verbose=False):
'''
Return the row n of the matrix.
'''
if verbose == True:
print(f'matrix[row={n}]...')
print(self.matrix[n])
return self.matrix[n]
def get_col(self, n, verbose=False):
'''
Return the column n of the matrix.
'''
column_items = []
i = 0
while i < self.rows:
column_items.append(self.matrix[i][n])
i += 1
if verbose == True:
print(f'matrix[col={n}]...')
for item in column_items:
print(item)
return column_items
def get_cell(self, row, col, verbose=False):
'''
Return a specific cell of the matrix.
'''
if verbose == True:
print(f'cell[row={row}, col={col}]...')
print(self.matrix[row][col])
return self.matrix[row][col]
def write_cell(self, row, col, data, verbose=False):
'''
Assign some data to a specific cell of the matrix.
'''
self.matrix[row][col] = data
if verbose == True:
print('Data wrote into cell[row={row}, col={col}]...')
print(self.matrix[row][col])
return self.matrix[row][col]
Test:
print('#########')
m = Matrix2D()
m.generate(4,5,True)
m.printme()
m.get_row(1,True)
m.get_col(1,True)
m.get_cell(3,2,True)
m.write_cell(3,2, (9,9,9),True)
Output:
#########
Generated a 4 row/s by 5 column/s matrix
----------------------------------------
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
[(1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]
[(2, 0), (2, 1), (2, 2), (2, 3), (2, 4)]
[(3, 0), (3, 1), (3, 2), (3, 3), (3, 4)]
----------------------------------------
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)]
[(1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]
[(2, 0), (2, 1), (2, 2), (2, 3), (2, 4)]
[(3, 0), (3, 1), (3, 2), (3, 3), (3, 4)]
matrix[row=1]...
[(1, 0), (1, 1), (1, 2), (1, 3), (1, 4)]
matrix[col=1]...
(0, 1)
(1, 1)
(2, 1)
(3, 1)
cell[row=3, col=2]...
(3, 2)
Data wrote into cell[row={row}, col={col}]...
(9, 9, 9)
Next, you can add some extra methods for more fancy operations like matrix multiplication, transposition etc... Have fun!

Related

Loop through list of tuples and unpack elements of each tuple

I have this list of two-value tuples
stake_odds=[(0, 1), (0, 2), (0, 5), (0, 10), (2, 1), (2, 2), **(2, 5)**, (2, 10), (5, 1), (5, 2), (5, 5), (5, 10), (10, 1), (10, 2), (10, 5), (10, 10)]
I have the following function where I want to put the tuple into an object method where it calculates the product (or minus product depending on the instance) of the two numbers in the tuple. If the product is positive, I want to append the tuple used to another list, pos_cases.
def function():
pos_cases=[]
x,y=stake_odds[9]
b1=bet1.payout(x,y)
if b1 > 0:
return b1, "b is greater than zero!"
pos_cases.append(stake_odds[9])
print(pos_cases)
print(function())
As you can see below I have to unpack the tuple into two variables before computing. I can do it by specifying the element of the list (stake_odds[9]), however I am looking for a way to generalize and loop through the list (stake_odds[i]) rather than going one by one.
The list in this example would be shortened to the following:
pos_cases =[(2, 1), (2, 2), (2, 5), (2, 10), (5, 1), (5, 2), (5, 5), (5, 10), (10, 1), (10, 2), (10, 5), (10, 10)]
How could I do this? The only thing I can think of is some nested for loop like:
for i in stake_odds:
for x,y in i:
return(x,y)
But this results in error >TypeError: cannot unpack non-iterable int object>.
Doesn't this work?:
def function():
pos_cases=[]
for x,y in stake_odds:
b1=bet1.payout(x,y)
if b1 > 0:
return b1, "b is greater than zero!"
pos_cases.append((x,y))
return pos_cases
print(function())

Simulate a liquid flow through a randomly created square matrix that contains a set of integers from 0-9 using Python [duplicate]

This question already has an answer here:
Stimulating Liquid Flow on Matrix
(1 answer)
Closed 2 years ago.
Simulate a liquid flow through a randomly created square matrix that contains a set of integers from 0-9 using Python. The liquid should start from the top left corner of the matrix. It could only move towards right or below adjacent matrix. The lower value of the adjacent matrix, the higher potential for it to flow. In the case of the right and below adjacent matrix have the same value, the program should be able to simulate both conditions (Refer attached example image). The movement of the liquid is considered stop at the right or below edge of the matrix. The program should be able to show the sum of all numbers that the liquid has pass through, in all possibilities and visualize the path. Visualization can be done by replacing the numbers lying in the path with asterisk (*) , vertical line/pipe symbol (|), hyphen (-) or other relevant symbols such as (~,>= etc). Other methods to visualize can be accepted. Example output should look like this:
Example output visualization
This is what i have coded so far, but it does not output all the possible outcomes and the sum of integers in which the liquid flows through;
import random
import numpy as np
import copy
a=[]
n=int(input("Enter matrix size between 8 to 20 only= "))
while True:
if n<8:
n=int(input("Input size less than 8! Enter at least 8 or more = "))
elif n>20:
n=int(input("Input size more than 20! Enter at most 20 or lesser = "))
else:
break
print()
print(f'{n} × {n} matrix generated from random numbers of 0-9 :\n')
def create_matrix(n, a):
for i in range (n):
v=[]
for j in range (n):
v.append(random.randint(0,9))
a.append(v)
my.create_matrix(n, a)
b=copy.deepcopy(a)
#c=copy.deepcopy(a)
def print_array(n, array):
for i in range(n):
for j in range(n):
print(array[i][j], end=" ")
print()
print()
my.print_array(n, a)
def move_right(b, i, j, n):
b[0][0]="."
while i+1 < n and j+1<n :
if b[i+1][j] < b[i][j+1]:
b[i+1][j]="."
i+=1
elif b[i][j+1] < b[i+1][j]:
b[i][j+1]="."
j+=1
elif b[i+1][j] == b[i][j+1]:
b[i][j]="*"
#c=copy.deepcopy(b)
#move_bottom(c, i, j, n)
b[i][j+1]="."
j+=1
else:
break
def move_bottom(array,i ,j, n):
array[i][j]="."
alt=0
while i+1 < n and j+1<n :
if array[i+1][j] < array[i][j+1]:
array[i+1][j]="."
i+=1
elif array[i][j+1] < array[i+1][j]:
array[i][j+1]="."
j+=1
elif array[i+1][j] == array[i][j+1]:
array[i][j]="*"
bb=copy.deepcopy(array)
move_right(bb,i,j,n)
array[i+1][j]="."
i+=1
alt+=1
else:
break
print_array(n, array)
my.move_bottom(b, 0, 0, n)
I really need help with my coding so that i can output all the possible outcomes that the liquid can flow and the sum of integers in which the liquid flows through. If there's any other way to easily code this program using python given the conditions, please let me know!
Here is how you could do this for all possible ways.
A map of
456
867
978
would be represented as dictionary of dictionaries:
{ (0,0): {(1,0): {(2,0): {},
(1,1): { (2,1): {},
(1,2): {}}}}
and can be used to generate all paths from it.
Then you need a copy of the original numbers and can add the ascii art instead of the numbers at the correct positions. The total map has to check if you add another way to a formerly already set position, and if so replace it with a "both-ways" marker.
Some utility-methods:
import random
import copy
random.seed(42) # fixed for repeatability
class Consts:
"""Some constants to use throughout"""
VALUES = range(10)
SIZE = 8
START = (0,0)
OUT_OF_BOUNDS = 99
def generate():
"""Generates an Consts.SIZE * Consts.SIZE list of lists of numbers 0-9"""
n = Consts.SIZE
data = random.choices(Consts.VALUES, k = n*n)
return [data[i * n : i * n + n] for i in range(n)]
def v(data, x, y):
"""Returns the value in data at position x,y or
Consts.OUT_OF_BOUNDS if out of bounds."""
try:
return data[y][x]
except:
return Consts.OUT_OF_BOUNDS
def peek_east(data, pos):
"""Returs the value, position tuple of the position one to the east"""
new_pos = pos[0] + 1, pos[1]
return v(data, *new_pos), new_pos
def peek_south(data, pos):
"""Returs the value, position tuple of the position one to the south"""
new_pos = pos[0], pos[1] + 1
return v(data, *new_pos), new_pos
def done(pos):
"""Returns True if a position is at the border of the map"""
return Consts.SIZE-1 in pos
def pp(arr):
"""Pretty print a map / list of lists"""
print('\n'.join(''.join(map(str, n)) for n in arr))
the exploration part:
def explore(data, start=None, ways=None):
"""Creates/Explores all the ways. The exploration position are stored
as dictionary that contains all explored tiles as a dict of dict of ...
of possible ways to go through the map."""
size = Consts.SIZE
OUT = Consts.OUT_OF_BOUNDS
start = start or Consts.START
ways = ways or {}
pos = start
if done(pos):
ways[pos] = "DONE"
return
routes = []
# get east and south data to see where we can go from here
east, east_pos = peek_east(data, pos)
south, south_pos = peek_south(data, pos)
# where to move to
if east <= south:
routes.append(east_pos)
if east >= south:
routes.append(south_pos)
# add the visited tiles and the empty dicts for them to ways
for way in routes:
if pos not in ways:
ways[pos] = {}
if way not in ways:
ways[way] = {}
ways[pos][way] = ways[way]
# explore further
for way in routes:
explore(data, way, ways)
# simplify dict, only return the (0,0) element
return {Consts.START: ways[Consts.START]}
How to use it & ascii art:
array = generate()
pp(array)
exp = explore(array)
# used to create all possible paths from the dict we generated
def get_paths(tree, cur=()):
""" Source: https://stackoverflow.com/a/11570745/7505395 """
if not tree or tree == "DONE":
yield cur
else:
for n, s in tree.items():
for path in get_paths(s, cur+(n,)):
yield path
p = list(get_paths(exp))
# copy the original map for a "all in one" map
d_all = copy.deepcopy(array)
for path in p:
# copy the original map for this paths map
d = copy.deepcopy(array)
# get from,to pairs from this runway
for (_from, _to) in zip(path, path[1:]):
_, pe = peek_east(array, _from)
_, ps = peek_south(array, _from)
# ASCII Art the map
if _to == pe:
d[_from[1]][_from[0]] = "-"
d_all[_from[1]][_from[0]] = "-" if isinstance(d_all[_from[1]][_from[0]], int) else ("-" if d_all[_from[1]][_from[0]] == "-" else "+")
else:
d[_from[1]][_from[0]] = "|"
d_all[_from[1]][_from[0]] = "|" if isinstance(d_all[_from[1]][_from[0]], int) else ("|" if d_all[_from[1]][_from[0]] == "|" else "+")
# ASCII Art the last one
d[_to[1]][_to[0]] = "°"
d_all[_to[1]][_to[0]] = "°"
# print this map
print("\nPath: ", path)
pp(d)
# and total map
print("\nTotal mapping")
pp(d_all)
Output:
60227680
40250165
25808631
93008687
59358685
70220212
63322966
17139656
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1),
(6, 2), (7, 2))
-|227680
4-----|5
258086-°
93008687
59358685
70220212
63322966
17139656
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (5, 2),
(6, 2), (7, 2))
-|227680
4----|65
25808--°
93008687
59358685
70220212
63322966
17139656
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3), (3, 4),
(3, 5), (4, 5), (5, 5), (6, 5), (7, 5))
-|227680
4--|0165
258|8631
930|8687
593|8685
702----°
63322966
17139656
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3), (3, 4),
(3, 5), (4, 5), (4, 6), (5, 6), (6, 6), (6, 7))
-|227680
4--|0165
258|8631
930|8687
593|8685
702-|212
6332--|6
171396°6
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3), (3, 4),
(3, 5), (4, 5), (4, 6), (5, 6), (5, 7))
-|227680
4--|0165
258|8631
930|8687
593|8685
702-|212
6332-|66
17139°56
Path: ((0, 0), (1, 0), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3), (3, 4),
(3, 5), (4, 5), (4, 6), (4, 7))
-|227680
4--|0165
258|8631
930|8687
593|8685
702-|212
6332|966
1713°656
Total mapping
-|227680
4--+-+|5
258|8--°
930|8687
593|8685
702-+--°
6332++|6
1713°°°6

Remove duplicate unordered tuples from list

In a list of tuples, I want to have just one copy of a tuple where it may be (x, y) or (y, x).
So, in:
# pairs = list(itertools.product(range(3), range(3)))
pairs = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
the result should be:
result = [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)] # updated pairs
This list of tuples is generated using itertools.product() but I want to remove the duplicates.
My working solution:
pairs = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
result = []
for pair in pairs:
a, b = pair
# reordering in increasing order
temp = (a, b) if a < b else (b, a)
result.append(temp)
print(list(set(result))) # I could use sorted() but the order doesn't matter
How can this be improved?
You could use combinations_with_replacement
The code for combinations_with_replacement() can be also expressed as a subsequence of product() after filtering entries where the elements are not in sorted order (according to their position in the input pool)
import itertools
pairs = list(itertools.combinations_with_replacement(range(3), 2))
print(pairs)
>>> [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]
edit I just realized, your solution matches my solution. What you are doing is just fine. If you need to do this for a very large list, then there are some other options you may want to look into, like a key value store.
If you need to remove dupes more programatically, then you can use a function like this:
def set_reduce(pairs):
new_pairs = set([])
for x,y in pairs:
if x < y:
new_pairs.add((x,y))
else:
new_pairs.add((y,x))
return new_pairs
running this results in
>>>set_reduce(pairs)
set([(0, 1), (1, 2), (0, 0), (0, 2), (2, 2), (1, 1)])
This is one solution which relies on sparse matrices. This works for the following reasons:
An entry in a matrix cannot contain two values. Therefore, uniqueness is guaranteed.
Selecting the upper triangle ensures that (0, 1) is preferred above (1, 0), and inclusion of both is not possible.
import numpy as np
from scipy.sparse import csr_matrix, triu
lst = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1),
(1, 2), (2, 0), (2, 1), (2, 2)]
# get row coords & col coords
d1, d2 = list(zip(*lst))
# set up sparse matrix inputs
row, col, data = np.array(d1), np.array(d2), np.array([1]*len(lst))
# get upper triangle of matrix including diagonal
m = triu(csr_matrix((data, (row, col))), 0)
# output coordinates
result = list(zip(*(m.row, m.col)))
# [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]

Shorten a list of tuples by cutting out loops?

I have a function that generates a list of tuples like:
[(0, 0), (1, 1), (1, 2), (1,3), (2, 4), (3, 5), (4, 5)]
which are used to represent a path of tiles (row, column) in a game I'm making.
The function that I use to generate these paths isn't perfect, since it often produces "loops", as shown below:
[(2, 0), (2, 1), (1, 2), (0, 3), (0, 4), (1, 5), (2, 5), (3, 4), (3, 3),
(3, 2), (4, 1)]
The path above should instead look like:
[(2, 0), (2, 1), (3, 2), (4, 1)]
These paths can contain any number of loops, which can be of any size and shape.
So my question is, how do I write a function in python that cuts the loopy list and returns a new, shorter list that does not have these loops.
My attempt below:
def Cut_Out_Loops(Path):
NewList = list(Path)
Cutting = True
a = 0
for Cords in Path:
a += 1
try:
for i in range(a + 2, len(Path)):
if (Path[i][0] == Cords[0] and abs(Path[i][1] - Cords[1]) == 1:
NewList = NewList[0:a] + NewList[i:]
Path = list(NewList)
elif Path[i][1] == Cords[1] and abs(Path[i][0] - Cords[0]) == 1:
NewList = NewList[0:a] + NewList[i:]
Path = list(NewList)
elif abs(Path[i][0] - Cords[0]) == 1 and abs(Path[i][1] - Cords[1]) == 1:
NewList = NewList[0:a] + NewList[i:]
Path = list(NewList)
elif abs(Path[i][1] - Cords[1]) == 1 and abs(Path[i][0] - Cords[0]) == 1:
NewList = NewList[0:a] + NewList[i:]
Path = list(NewList)
Cutting = False
except IndexError:
Cutting = True
Although your definition of a "loop" isn't too clear, try this
def clean(path):
path1 = []
for (x1,y1) in path:
for (i,(x2,y2)) in enumerate(path1[:-1]):
if abs(x1-x2) <= 1 and abs(y1-y2) <= 1:
path1 = path1[:i+1]
break
path1.append((x1,y1))
return path1
It definitely works for your example:
>>> path = [(2, 0), (2, 1), (1, 2), (0, 3), (0, 4), (1, 5), (2, 5), (3, 4), (3, 3), (3, 2), (4, 1)]
>>> clean(path)
[(2, 0), (2, 1), (3, 2), (4, 1)]
That said, it is just the most straightforward of brute force solutions. The complexity is quadratic.
How long are your paths? If they're all under 1000 elements, even a naive brute-force algorithm would work:
path = [
(2, 0),
(2, 1),
(1, 2),
(0, 3),
(0, 4),
(1, 5),
(2, 5),
(3, 4),
(3, 3),
(3, 2),
(4, 1)
]
def adjacent(elem, next_elem):
return (abs(elem[0] - next_elem[0]) <= 1 and
abs(elem[1] - next_elem[1]) <= 1)
new_path = []
i = 0
while True:
elem = path[i]
new_path.append(elem)
if i + 1 == len(path):
break
j = len(path) - 1
while True:
future_elem = path[j]
if adjacent(elem, future_elem):
break
j -= 1
i = j
print new_path

format and Print a list in a file

i have one list with some coordinates in it, when i am printing it like that:
for i in range(0,len(List)):
print("".join(["(%d, %d) \n" % (y[i], y[i+1]) for y in (List)]))
the output is this:
(0, 3)
(0, 2)
(0, 1)
(1, 1)
(1, 2)
(2, 2)
(2, 1)
(3, 1)
(3, 0)
(2, 0)
(1, 0)
(0, 0)
i want to save the output in a .txt, but that is not a problem, my problem is that the .txt must be formmated like this:
(0, 3), (0, 2)
(0, 2), (0, 1)
(0, 1),(1, 1)
(1, 1),(1, 2)
(1, 2),(2, 2)
.....
i've tried many things but nothing worked..
it must be easy, but i am new to python
thank you in advance
This does the trick:
l = [(0, 3), (0, 2), (0, 1), (1, 1), (1, 2), (2, 2)]
for i in range(0, len(l), 2):
print(', '.join([str(l[i]), str(l[i+1])]))
# (0, 3), (0, 2)
# (0, 1), (1, 1)
# (1, 2), (2, 2)
You can use zip.
mylist = [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# That doesn't have to be the numbers though, you can use your own.
for a, b in zip(mylist, mylist[1:]):
print("{}, {}".format(a, b), file = myfile) # Will print to myfile.
That's assuming that you are printing to an open file. Leave the file argument out if you don't want to print anywhere else, but the default screen.
in myfile.txt:
(0, 0), (0, 1)
(0, 1), (0, 2)
(0, 2), (1, 0)
(1, 0), (1, 1)
(1, 1), (1, 2)
(1, 2), (2, 0)
(2, 0), (2, 1)
(2, 1), (2, 2)
The output is in tuples, not lists.
Well, besides other answers playing with indices, you can also use zip:
for a, b, c, d in zip(List, List[1:], List[2:], List[3:]):
print('({}, {}), ({}, {})'.format(a, b, c, d))
Regarding expected output:
l = [(0, 3), (0, 2), (0, 1), (1, 1), (1, 2), (2, 2)]
for i,j in zip(l,l[1:]):
print str(i) + "," + str(j) # or print ",".join([str(i),str(j)])
#output
(0, 3),(0, 2)
(0, 2),(0, 1)
(0, 1),(1, 1)
(1, 1),(1, 2)
(1, 2),(2, 2)
If you want list chunking with 2 elements,Try this
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]
for i,j in list(chunks(l,2)):
print ",".join([str(i),str(j)])
#output
(0, 3),(0, 2)
(0, 1),(1, 1)
(1, 2),(2, 2)
Your code:
for i in range(0,len(List)):
print("".join(["(%d, %d) \n" % (y[i], y[i+1]) for y in (List)]))
Turning this into a list comp.
t = ["".join(["(%d, %d) \n" % (y[i], y[i+1]) for y in (List)]) for i in range(0,len(List))]
(equivalent to)
s = []
for i in range(0,len(List)):
s.append("".join(["(%d, %d) \n" % (y[i], y[i+1]) for y in (List)]))
Then:
first = True
other = None
r = ""
for i in t:
if not first:
r += other+", "+i+"\n"
first = True
else:
other = i
first = False
f = open("out.txt","w")
f.write(t)
f.close() #go to notepad

Categories

Resources