├── Data structure analysis .pdf ├── README.md ├── output.txt ├── sample.exp ├── sampleCommands.in ├── sampleData.txt ├── spreadsheet ├── __pycache__ │ ├── arraySpreadsheet.cpython-311.pyc │ ├── baseSpreadsheet.cpython-311.pyc │ ├── cell.cpython-311.pyc │ ├── csrSpreadsheet.cpython-311.pyc │ └── linkedlistSpreadsheet.cpython-311.pyc ├── arraySpreadsheet.py ├── baseSpreadsheet.py ├── cell.py ├── csrSpreadsheet.py └── linkedlistSpreadsheet.py └── spreadsheetFilebased.py /Data structure analysis .pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/Data structure analysis .pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Spreadsheets are an essential application, for anyone needing to record and share tabular data. 2 | While not the most exciting of applications, they are the workhorse of data analysis and professional services and provide an ideal application setting for studying data structures and their efficiencies. 3 | In this assignment, we will focus on implementing data structures needed for developing a spreadsheet application. We will develop several data structures and compare their performances. 4 | These data structures are arrays (that is, Python list), linked lists and Compressed Sparse Rows (CSR), which will be further described below. 5 | -------------------------------------------------------------------------------- /output.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/output.txt -------------------------------------------------------------------------------- /sample.exp: -------------------------------------------------------------------------------- 1 | Call to appendRow() returned success. 2 | Call to appendCol() returned success. 3 | Printing output of find(6.0): (3,1) 4 | Printing output of find(-6.0): 5 | Printing output of find(-6.7): (8,5) 6 | Number of rows = 11 7 | Number of columns = 11 8 | Call to update(2,5,-1.0) returned success. 9 | Call to update(10,10,1.0) returned success. 10 | Call to update(11,11,2.5) returned failure. 11 | Printing output of entries(): (2,5,-1.00) | (3,1,6.00) | (8,5,-6.70) | (9,9,2.00) | (10,10,1.00) 12 | Call to insertRow(1) returned success. 13 | Call to insertCol(4) returned success. 14 | Call to insertRow(-2) returned failure. 15 | Number of rows = 12 16 | Number of columns = 12 17 | Printing output of entries(): (3,6,-1.00) | (4,1,6.00) | (9,6,-6.70) | (10,10,2.00) | (11,11,1.00) 18 | Call to update(2,5,-2.0) returned success. 19 | Printing output of entries(): (2,5,-2.00) | (3,6,-1.00) | (4,1,6.00) | (9,6,-6.70) | (10,10,2.00) | (11,11,1.00) 20 | -------------------------------------------------------------------------------- /sampleCommands.in: -------------------------------------------------------------------------------- 1 | AR 2 | AC 3 | F 6 4 | F -6 5 | F -6.7 6 | R 7 | C 8 | U 2 5 -1 9 | U 10 10 1 10 | U 11 11 2.5 11 | E 12 | IR 1 13 | IC 4 14 | IR -2 15 | R 16 | C 17 | E 18 | U 2 5 -2 19 | E 20 | -------------------------------------------------------------------------------- /sampleData.txt: -------------------------------------------------------------------------------- 1 | 9 9 2.0 2 | 2 5 7 3 | 3 1 6 4 | 8 5 -6.7 -------------------------------------------------------------------------------- /spreadsheet/__pycache__/arraySpreadsheet.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/spreadsheet/__pycache__/arraySpreadsheet.cpython-311.pyc -------------------------------------------------------------------------------- /spreadsheet/__pycache__/baseSpreadsheet.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/spreadsheet/__pycache__/baseSpreadsheet.cpython-311.pyc -------------------------------------------------------------------------------- /spreadsheet/__pycache__/cell.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/spreadsheet/__pycache__/cell.cpython-311.pyc -------------------------------------------------------------------------------- /spreadsheet/__pycache__/csrSpreadsheet.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/spreadsheet/__pycache__/csrSpreadsheet.cpython-311.pyc -------------------------------------------------------------------------------- /spreadsheet/__pycache__/linkedlistSpreadsheet.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjaDevOps0831/spreadsheet-data-structure/6f7253f595e9c644c37658f8b3ee6b6d6c722d7b/spreadsheet/__pycache__/linkedlistSpreadsheet.cpython-311.pyc -------------------------------------------------------------------------------- /spreadsheet/arraySpreadsheet.py: -------------------------------------------------------------------------------- 1 | from spreadsheet.cell import Cell 2 | from spreadsheet.baseSpreadsheet import BaseSpreadsheet 3 | 4 | 5 | # ------------------------------------------------------------------------ 6 | # This class is required TO BE IMPLEMENTED 7 | # Array-based spreadsheet implementation. 8 | # 9 | # __author__ = 'Jeffrey Chan' 10 | # __copyright__ = 'Copyright 2023, RMIT University' 11 | # ------------------------------------------------------------------------ 12 | 13 | class ArraySpreadsheet(BaseSpreadsheet): 14 | 15 | def __init__(self): 16 | self.data = [] 17 | self.c_row = 0 18 | self.c_col = 0 19 | 20 | 21 | def buildSpreadsheet(self, lCells: [Cell]): 22 | """ 23 | Construct the data structure to store nodes. 24 | @param lCells: list of cells to be stored 25 | """ 26 | 27 | for lCell in lCells: 28 | if (lCell.row >= self.c_row): 29 | for i in range(self.c_row, lCell.row + 1): 30 | self.data.append([]) 31 | 32 | self.c_row = lCell.row + 1 33 | 34 | if (lCell.col >= self.c_col): 35 | self.c_col = lCell.col + 1 36 | 37 | self.data[lCell.row].append(lCell) 38 | 39 | self.data[lCell.row] = sorted(self.data[lCell.row], 40 | key=lambda cell: cell.col) 41 | 42 | 43 | def appendRow(self)->bool: 44 | """ 45 | Appends an empty row to the spreadsheet. 46 | 47 | @return True if operation was successful, or False if not. 48 | """ 49 | 50 | self.data.append([]) 51 | self.c_row += 1 52 | 53 | return True 54 | 55 | 56 | def appendCol(self)->bool: 57 | """ 58 | Appends an empty column to the spreadsheet. 59 | 60 | @return True if operation was successful, or False if not. 61 | """ 62 | 63 | self.c_col += 1 64 | 65 | return True 66 | 67 | 68 | def insertRow(self, rowIndex: int)->bool: 69 | """ 70 | Inserts an empty row into the spreadsheet. 71 | 72 | @param rowIndex Index of the existing row that will be after the newly inserted row. If inserting as first row, specify rowIndex to be 0. If inserting a row after the last one, specify rowIndex to be rowNum()-1. 73 | 74 | @return True if operation was successful, or False if not, e.g., rowIndex is invalid. 75 | """ 76 | 77 | if (rowIndex >= 0 and rowIndex < self.c_row): 78 | for i in range(rowIndex, len(self.data)): 79 | for j in range(len(self.data[i])): 80 | self.data[i][j].row += 1 81 | 82 | self.data.insert(rowIndex, []) 83 | self.c_row += 1 84 | 85 | return True 86 | 87 | return False 88 | 89 | 90 | def insertCol(self, colIndex: int)->bool: 91 | """ 92 | Inserts an empty column into the spreadsheet. 93 | 94 | @param colIndex Index of the existing column that will be after the newly inserted row. If inserting as first column, specify colIndex to be 0. If inserting a column after the last one, specify colIndex to be colNum()-1. 95 | 96 | return True if operation was successful, or False if not, e.g., colIndex is invalid. 97 | """ 98 | 99 | if (colIndex > 0 and colIndex < self.c_col): 100 | for i in range(len(self.data)): 101 | for j in range(len(self.data[i])): 102 | if (self.data[i][j].col >= colIndex): 103 | self.data[i][j].col += 1 104 | 105 | self.c_col += 1 106 | 107 | return True 108 | 109 | return False 110 | 111 | 112 | def update(self, rowIndex: int, colIndex: int, value: float) -> bool: 113 | """ 114 | Update the cell with the input/argument value. 115 | 116 | @param rowIndex Index of row to update. 117 | @param colIndex Index of column to update. 118 | @param value Value to update. Can assume they are floats. 119 | 120 | @return True if cell can be updated. False if cannot, e.g., row or column indices do not exist. 121 | """ 122 | 123 | if (rowIndex < self.c_row and colIndex < self.c_col): 124 | for i in range(len(self.data[rowIndex])): 125 | if (self.data[rowIndex][i].col == colIndex): 126 | self.data[rowIndex][i].val = value 127 | 128 | return True 129 | 130 | new_cell = Cell(rowIndex, colIndex, value) 131 | self.data[rowIndex].append(new_cell) 132 | self.data[rowIndex] = sorted(self.data[rowIndex], 133 | key=lambda cell: cell.col) 134 | 135 | return True 136 | 137 | return False 138 | 139 | 140 | def rowNum(self)->int: 141 | """ 142 | @return Number of rows the spreadsheet has. 143 | """ 144 | return self.c_row 145 | 146 | 147 | def colNum(self)->int: 148 | """ 149 | @return Number of column the spreadsheet has. 150 | """ 151 | return self.c_col 152 | 153 | 154 | 155 | def find(self, value: float) -> [(int, int)]: 156 | """ 157 | Find and return a list of cells that contain the value 'value'. 158 | 159 | @param value value to search for. 160 | 161 | @return List of cells (row, col) that contains the input value. 162 | """ 163 | 164 | result : [(int, int)] = [] 165 | 166 | for i in range(len(self.data)): 167 | for j in range(len(self.data[i])): 168 | if (self.data[i][j].val == value): 169 | result.append((self.data[i][j].row,self.data[i][j].col)) 170 | 171 | return result 172 | 173 | 174 | 175 | def entries(self) -> [Cell]: 176 | """ 177 | @return A list of cells that have values (i.e., all non None cells). 178 | """ 179 | result : [Cell] = [] 180 | 181 | for i in range(len(self.data)): 182 | for j in range(len(self.data[i])): 183 | result.append(self.data[i][j]) 184 | 185 | return result 186 | -------------------------------------------------------------------------------- /spreadsheet/baseSpreadsheet.py: -------------------------------------------------------------------------------- 1 | from spreadsheet.cell import Cell 2 | 3 | 4 | # ------------------------------------------------- 5 | # Base class for spreadsheet implementations. DON'T CHANGE THIS FILE. 6 | # 7 | # __author__ = 'Jeffrey Chan' 8 | # __copyright__ = 'Copyright 2023, RMIT University' 9 | # ------------------------------------------------- 10 | 11 | class BaseSpreadsheet: 12 | def buildSpreadsheet(self, lCells: [Cell]): 13 | """ 14 | Construct the data structure to store nodes. 15 | @param lCells: list of cells to be stored 16 | """ 17 | pass 18 | 19 | 20 | def appendRow(self)->bool: 21 | """ 22 | Appends an empty row to the spreadsheet. 23 | 24 | @return True if operation was successful, or False if not. 25 | """ 26 | 27 | pass 28 | 29 | 30 | def appendCol(self)->bool: 31 | """ 32 | Appends an empty column to the spreadsheet. 33 | 34 | @return True if operation was successful, or False if not. 35 | """ 36 | 37 | pass 38 | 39 | 40 | def insertRow(self, rowIndex: int)->bool: 41 | """ 42 | Inserts an empty row into the spreadsheet. 43 | 44 | @param rowIndex Index of the existing row that will be after the newly inserted row. If inserting as first row, specify rowIndex to be 0. If inserting a row after the last one, specify rowIndex to be rowNum()-1. 45 | 46 | @return True if operation was successful, or False if not, e.g., rowIndex is invalid. 47 | """ 48 | 49 | pass 50 | 51 | 52 | def insertCol(self, colIndex: int)->bool: 53 | """ 54 | Inserts an empty column into the spreadsheet. 55 | 56 | @param colIndex Index of the existing column that will be after the newly inserted row. If inserting as first column, specify colIndex to be 0. If inserting a column after the last one, specify colIndex to be colNum()-1. 57 | 58 | return True if operation was successful, or False if not, e.g., colIndex is invalid. 59 | """ 60 | 61 | pass 62 | 63 | 64 | def update(self, rowIndex: int, colIndex: int, value: float) -> bool: 65 | """ 66 | Update the cell with the input/argument value. 67 | 68 | @param rowIndex Index of row to update. 69 | @param colIndex Index of column to update. 70 | @param value Value to update. Can assume they are floats. 71 | 72 | @return True if cell can be updated. False if cannot, e.g., row or column indices do not exist. 73 | """ 74 | 75 | pass 76 | 77 | 78 | def rowNum(self)->int: 79 | """ 80 | @return Number of rows the spreadsheet has. 81 | """ 82 | 83 | return 0; 84 | 85 | 86 | def colNum(self)->int: 87 | """ 88 | @return Number of column the spreadsheet has. 89 | """ 90 | 91 | return 0; 92 | 93 | 94 | def find(self, value: float) -> [(int, int)]: 95 | """ 96 | Find and return a list of cells that contain the value 'value'. 97 | 98 | @param value value to search for. 99 | 100 | @return List of cells (row, col) that contains the input value. 101 | """ 102 | 103 | pass 104 | 105 | 106 | def entries(self) -> [Cell]: 107 | """ 108 | @return A list of cells that have values (i.e., all non None cells). 109 | """ 110 | 111 | return [] 112 | -------------------------------------------------------------------------------- /spreadsheet/cell.py: -------------------------------------------------------------------------------- 1 | 2 | # ------------------------------------------------- 3 | # __author__ = 'Jeffrey Chan' 4 | # __copyright__ = 'Copyright 2023, RMIT University' 5 | # ------------------------------------------------- 6 | 7 | # Class representing a cell and its value. 8 | class Cell: 9 | def __init__(self, row: int, col: int, val: float): 10 | # a cell object has the row, column and value 11 | self.row = row 12 | self.col = col 13 | self.val = val 14 | 15 | def __str__(self) -> str: 16 | """ 17 | Convert cell to a string for printing. 18 | """ 19 | 20 | return "(" + str(self.row) + "," + str(self.col) + "," + "{:.2f}".format(self.val) + ")" 21 | -------------------------------------------------------------------------------- /spreadsheet/csrSpreadsheet.py: -------------------------------------------------------------------------------- 1 | from spreadsheet.baseSpreadsheet import BaseSpreadsheet 2 | from spreadsheet.cell import Cell 3 | import numpy as np 4 | from scipy.sparse import csr_matrix, find 5 | 6 | 7 | # ------------------------------------------------------------------------ 8 | # This class is required TO BE IMPLEMENTED 9 | # Trie-based dictionary implementation. 10 | # 11 | # __author__ = 'Jeffrey Chan' 12 | # __copyright__ = 'Copyright 2023, RMIT University' 13 | # ------------------------------------------------------------------------ 14 | 15 | 16 | 17 | 18 | class CSRSpreadsheet(BaseSpreadsheet): 19 | 20 | def __init__(self): 21 | 22 | self.c_row = 0 23 | self.c_col = 0 24 | 25 | pass 26 | 27 | 28 | def buildSpreadsheet(self, lCells: [Cell]): 29 | """ 30 | Construct the data structure to store nodes. 31 | @param lCells: list of cells to be stored 32 | """ 33 | 34 | # TO BE IMPLEMENTED 35 | cnt = 0 36 | max_row = 0 37 | max_col = 0 38 | datacount = len(lCells) 39 | rcv = np.zeros(shape = (3, datacount)) 40 | for lCell in lCells: 41 | rcv[0,cnt] = lCell.row 42 | rcv[1,cnt] = lCell.col 43 | rcv[2,cnt] = lCell.val 44 | cnt = cnt+1 45 | if(max_row < lCell.row): 46 | max_row = lCell.row 47 | if(max_col < lCell.col): 48 | max_col = lCell.col 49 | 50 | self.matrix = csr_matrix((rcv[2], (rcv[0], rcv[1])), shape=(max_row+1, max_col+1)) 51 | 52 | self.c_row = max_row+1 53 | self.c_col = max_col+1 54 | 55 | pass 56 | 57 | 58 | def appendRow(self): 59 | """ 60 | Appends an empty row to the spreadsheet. 61 | 62 | @return True if operation was successful, or False if not. 63 | """ 64 | 65 | # TO BE IMPLEMENTED 66 | rcv = find(self.matrix) 67 | 68 | newrcv = np.zeros(shape = (3, len(rcv[2]) + 1)) 69 | 70 | for i in range(len(rcv[2])): 71 | newrcv[0,i] = rcv[0][i] 72 | newrcv[1,i] = rcv[1][i] 73 | newrcv[2,i] = rcv[2][i] 74 | newrcv[0,len(rcv[2])] = self.c_row 75 | newrcv[1,len(rcv[2])] = self.c_col-1 76 | newrcv[2,len(rcv[2])] = 0 77 | self.matrix = csr_matrix((newrcv[2], (newrcv[0], newrcv[1])), shape=(self.c_row+1, self.c_col)) 78 | 79 | self.c_row = self.c_row + 1 80 | return True 81 | 82 | pass 83 | 84 | 85 | def appendCol(self): 86 | """ 87 | Appends an empty column to the spreadsheet. 88 | 89 | @return True if operation was successful, or False if not. 90 | """ 91 | rcv = find(self.matrix) 92 | newrcv = np.zeros(shape = (3, len(rcv[2]) + 1)) 93 | 94 | for i in range(len(rcv[2])): 95 | newrcv[0,i] = rcv[0][i] 96 | newrcv[1,i] = rcv[1][i] 97 | newrcv[2,i] = rcv[2][i] 98 | newrcv[0,len(rcv[2])] = self.c_row-1 99 | newrcv[1,len(rcv[2])] = self.c_col 100 | newrcv[2,len(rcv[2])] = 0 101 | self.matrix = csr_matrix((newrcv[2], (newrcv[0], newrcv[1])), shape=(self.c_row, self.c_col+1)) 102 | 103 | self.c_col = self.c_col + 1 104 | return True 105 | pass 106 | 107 | 108 | def insertRow(self, rowIndex: int)->bool: 109 | """ 110 | Inserts an empty row into the spreadsheet. 111 | 112 | @param rowIndex Index of the existing row that will be after the newly inserted row. If inserting as first row, specify rowIndex to be 0. If inserting a row after the last one, specify rowIndex to be rowNum()-1. 113 | 114 | @return True if operation was successful, or False if not, e.g., rowIndex is invalid. 115 | """ 116 | if(rowIndex < 0 ): 117 | return False 118 | if(rowIndex > self.c_row-1 ): 119 | return False 120 | rcv = find(self.matrix) 121 | newrcv = np.zeros(shape = (3, len(rcv[2]) + 1)) 122 | for i in range(len(rcv[2])): 123 | if(rcv[0][i] >= rowIndex): 124 | newrcv[0,i] = rcv[0][i]+1 125 | else: 126 | newrcv[0,i] = rcv[0][i] 127 | newrcv[1,i] = rcv[1][i] 128 | newrcv[2,i] = rcv[2][i] 129 | 130 | 131 | newrcv[0,len(rcv[2])] = self.c_row 132 | newrcv[1,len(rcv[2])] = self.c_col-1 133 | newrcv[2,len(rcv[2])] = 0 134 | self.matrix = csr_matrix((newrcv[2], (newrcv[0], newrcv[1])), shape=(self.c_row+1, self.c_col)) 135 | 136 | self.c_row = self.c_row + 1 137 | return True 138 | 139 | 140 | def insertCol(self, colIndex: int)->bool: 141 | """ 142 | Inserts an empty column into the spreadsheet. 143 | 144 | @param colIndex Index of the existing column that will be after the newly inserted row. If inserting as first column, specify colIndex to be 0. If inserting a column after the last one, specify colIndex to be colNum()-1. 145 | 146 | return True if operation was successful, or False if not, e.g., colIndex is invalid. 147 | """ 148 | if(colIndex < 0 ): 149 | return False 150 | if(colIndex > self.c_col-1 ): 151 | return False 152 | rcv = find(self.matrix) 153 | newrcv = np.zeros(shape = (3, len(rcv[2])+1)) 154 | for i in range(len(rcv[2])): 155 | if(rcv[1][i] >= colIndex): 156 | newrcv[1,i] = rcv[1][i]+1 157 | else: 158 | newrcv[1,i] = rcv[1][i] 159 | newrcv[0,i] = rcv[0][i] 160 | newrcv[2,i] = rcv[2][i] 161 | 162 | 163 | newrcv[0,len(rcv[2])] = self.c_row-1 164 | newrcv[1,len(rcv[2])] = self.c_col 165 | newrcv[2,len(rcv[2])] = 0 166 | self.matrix = csr_matrix((newrcv[2], (newrcv[0], newrcv[1])), shape=(self.c_row, self.c_col+1)) 167 | 168 | self.c_col = self.c_col+1 169 | 170 | # REPLACE WITH APPROPRIATE RETURN VALUE 171 | return True 172 | 173 | 174 | 175 | def update(self, rowIndex: int, colIndex: int, value: float) -> bool: 176 | """ 177 | Update the cell with the input/argument value. 178 | 179 | @param rowIndex Index of row to update. 180 | @param colIndex Index of column to update. 181 | @param value Value to update. Can assume they are floats. 182 | 183 | @return True if cell can be updated. False if cannot, e.g., row or column indices do not exist. 184 | """ 185 | 186 | # TO BE IMPLEMENTED 187 | 188 | # REPLACE WITH APPROPRIATE RETURN VALUE 189 | if(colIndex < 0 or colIndex >= self.c_col): 190 | return False 191 | if(rowIndex < 0 or rowIndex >= self.c_row): 192 | return False 193 | rcv = find(self.matrix) 194 | newrcv = np.zeros(shape = (3, len(rcv[2])+1)) 195 | isExist = False 196 | for i in range(len(rcv[2])): 197 | newrcv[0,i] = rcv[0][i] 198 | newrcv[1,i] = rcv[1][i] 199 | newrcv[2,i] = rcv[2][i] 200 | if(rcv[0][i] == rowIndex and rcv[1][i] == colIndex): 201 | rcv[2][i] = value 202 | isExist = True 203 | if(isExist): 204 | self.matrix = csr_matrix((rcv[2], (rcv[0], rcv[1])), shape=(self.c_row, self.c_col)) 205 | return True 206 | else: 207 | newrcv[0,len(rcv[2])] = rowIndex 208 | newrcv[1,len(rcv[2])] = colIndex 209 | newrcv[2,len(rcv[2])] = value 210 | self.matrix = csr_matrix((newrcv[2], (newrcv[0], newrcv[1])), shape=(self.c_row, self.c_col)) 211 | return True 212 | 213 | 214 | 215 | 216 | def rowNum(self)->int: 217 | """ 218 | @return Number of rows the spreadsheet has. 219 | """ 220 | # TO BE IMPLEMENTED 221 | 222 | return self.c_row 223 | 224 | 225 | def colNum(self)->int: 226 | """ 227 | @return Number of column the spreadsheet has. 228 | """ 229 | # TO BE IMPLEMENTED 230 | return self.c_col 231 | 232 | 233 | 234 | 235 | def find(self, value: float) -> [(int, int)]: 236 | """ 237 | Find and return a list of cells that contain the value 'value'. 238 | 239 | @param value value to search for. 240 | 241 | @return List of cells (row, col) that contains the input value. 242 | """ 243 | 244 | # TO BE IMPLEMENTED 245 | 246 | # REPLACE WITH APPROPRIATE RETURN VALUE 247 | result : [(int, int)] = [] 248 | rcv = find(self.matrix) 249 | for i in range(len(rcv[2])): 250 | if(rcv[2][i] == value): 251 | result.append((rcv[0][i],rcv[1][i])) 252 | 253 | return result 254 | 255 | 256 | 257 | 258 | def entries(self) -> [Cell]: 259 | """ 260 | return a list of cells that have values (i.e., all non None cells). 261 | """ 262 | result : [Cell] = [] 263 | data = self.matrix.toarray() 264 | for i in range(self.c_row): 265 | for j in range(self.c_col): 266 | if(data[i][j] != 0): 267 | result.append(Cell(i,j,data[i][j])) 268 | 269 | return result 270 | 271 | -------------------------------------------------------------------------------- /spreadsheet/linkedlistSpreadsheet.py: -------------------------------------------------------------------------------- 1 | from spreadsheet.baseSpreadsheet import BaseSpreadsheet 2 | from spreadsheet.cell import Cell 3 | 4 | 5 | # class ListNode: 6 | # ''' 7 | # Define a node in the linked list 8 | # ''' 9 | # 10 | # def __init__(self, word_frequency: WordFrequency): 11 | # self.word_frequency = word_frequency 12 | # self.next = None 13 | 14 | # ------------------------------------------------------------------------ 15 | # This class is required TO BE IMPLEMENTED 16 | # Linked-List-based spreadsheet implementation. 17 | # 18 | # __author__ = 'Jeffrey Chan' 19 | # __copyright__ = 'Copyright 2023, RMIT University' 20 | # ------------------------------------------------------------------------ 21 | 22 | 23 | class RowNode: 24 | ''' 25 | Define a row node 26 | ''' 27 | 28 | def __init__(self, row_num = None, next = None, prev = None): 29 | self.row_num = row_num 30 | self.next = None 31 | self.prev = None 32 | self.head = None 33 | 34 | 35 | class ColNode: 36 | ''' 37 | Define a column node 38 | ''' 39 | 40 | def __init__(self, col_num = None, cell_data = None, next = None, prev = None): 41 | self.col_num = col_num 42 | self.cell_data = cell_data 43 | self.next = None 44 | self.prev = None 45 | 46 | class LinkedListSpreadsheet(BaseSpreadsheet): 47 | 48 | def __init__(self): 49 | self.head = None 50 | self.c_row = 0 51 | self.c_col = 0 52 | 53 | 54 | 55 | 56 | def appendRow(self): 57 | """ 58 | Appends an empty row to the spreadsheet. 59 | """ 60 | self.c_row = self.c_row + 1 61 | return True 62 | 63 | 64 | def appendCol(self): 65 | """ 66 | Appends an empty column to the spreadsheet. 67 | 68 | @return True if operation was successful, or False if not. 69 | """ 70 | self.c_col = self.c_col+1 71 | return True 72 | 73 | 74 | def insertRow(self, rowIndex: int)->bool: 75 | """ 76 | Inserts an empty row into the spreadsheet. 77 | 78 | @param rowIndex Index of the existing row that will be after the newly inserted row. If inserting as first row, specify rowIndex to be 0. If inserting a row after the last one, specify rowIndex to be rowNum()-1. 79 | 80 | @return True if operation was successful, or False if not, e.g., rowIndex is invalid. 81 | """ 82 | if(rowIndex < 0 ): 83 | return False 84 | 85 | if(rowIndex > self.c_row-1 ): 86 | return False 87 | 88 | if(self.head == None): 89 | 90 | self.c_row = self.c_row + 1 91 | return True 92 | else: 93 | temp = self.head 94 | isOk = False 95 | while(temp != None): 96 | if(temp.row_num >= rowIndex): 97 | temp.row_num = temp.row_num + 1 98 | temp = temp.next 99 | 100 | self.c_row = self.c_row + 1 101 | return True 102 | 103 | 104 | 105 | def insertCol(self, colIndex: int)->bool: 106 | """ 107 | Inserts an empty column into the spreadsheet. 108 | 109 | @param colIndex Index of the existing column that will be before the newly inserted row. If inserting as first column, specify colIndex to be -1. 110 | """ 111 | if(colIndex < 0 ): 112 | return False 113 | if(colIndex > self.c_col-1 ): 114 | return False 115 | 116 | row = self.head 117 | 118 | while(row != None): 119 | 120 | col = row.head 121 | while(col != None): 122 | if(col.col_num >= colIndex): 123 | col.col_num = col.col_num + 1 124 | col = col.next 125 | row = row.next 126 | self.c_col = self.c_col + 1 127 | return True 128 | 129 | 130 | 131 | def update(self, rowIndex: int, colIndex: int, value: float) -> bool: 132 | """ 133 | Update the cell with the input/argument value. 134 | 135 | @param rowIndex Index of row to update. 136 | @param colIndex Index of column to update. 137 | @param value Value to update. Can assume they are floats. 138 | 139 | @return True if cell can be updated. False if cannot, e.g., row or column indices do not exist. 140 | """ 141 | 142 | if(colIndex < 0 or colIndex >= self.c_col): 143 | return False 144 | if(rowIndex < 0 or rowIndex >= self.c_row): 145 | return False 146 | if(self.head == None): 147 | row = RowNode(rowIndex) 148 | row = self.insertColinRow(row, ColNode(colIndex,value)) 149 | self.head = row 150 | return 151 | row = self.head 152 | prev:RowNode = None 153 | while(row != None): 154 | if(row.row_num == rowIndex): 155 | col = row.head 156 | while(col != None): 157 | if(col.col_num == colIndex): 158 | col.cell_data = value 159 | return True 160 | col = col.next 161 | self.insertColinRow(row, ColNode(colIndex,value)) 162 | return True 163 | elif(row.row_num > rowIndex): 164 | temp = self.insertRowinMatrix(RowNode(rowIndex), row) 165 | self.insertColinRow(temp, ColNode(colIndex,value)) 166 | return True 167 | prev = row 168 | row = row.next 169 | row = RowNode(rowIndex) 170 | self.insertColinRow(row, ColNode(colIndex,value)) 171 | prev.next = row 172 | 173 | return True 174 | 175 | 176 | def rowNum(self)->int: 177 | """ 178 | @return Number of rows the spreadsheet has. 179 | """ 180 | 181 | # TO BE IMPLEMENTED 182 | 183 | return self.c_row 184 | 185 | 186 | def colNum(self)->int: 187 | """ 188 | @return Number of column the spreadsheet has. 189 | """ 190 | 191 | return self.c_col 192 | 193 | 194 | 195 | def find(self, value: float) -> [(int, int)]: 196 | """ 197 | Find and return a list of cells that contain the value 'value'. 198 | 199 | @param value value to search for. 200 | 201 | @return List of cells (row, col) that contains the input value. 202 | """ 203 | 204 | result : [(int, int)] = [] 205 | row = self.head 206 | 207 | while(row != None): 208 | 209 | col = row.head 210 | while(col != None): 211 | if(col.cell_data == value): 212 | result.append((row.row_num,col.col_num)) 213 | col = col.next 214 | row = row.next 215 | return result 216 | 217 | 218 | 219 | def entries(self) -> [Cell]: 220 | """ 221 | @return A list of cells that have values (i.e., all non None cells). 222 | """ 223 | 224 | result : [Cell] = [] 225 | row = self.head 226 | 227 | while(row != None): 228 | col = row.head 229 | while(col != None): 230 | result.append(Cell(row.row_num, col.col_num, col.cell_data)) 231 | col = col.next 232 | row = row.next 233 | return result 234 | 235 | def insertColinRow(self,row:RowNode, col:ColNode): 236 | if(row.head == None): 237 | row.head = col 238 | return row 239 | else: 240 | temp:ColNode = row.head 241 | prev:ColNode = None 242 | while(temp != None): 243 | if(temp.col_num > col.col_num): 244 | 245 | if(temp == row.head): 246 | row.head = col 247 | col.next = temp 248 | temp.prev = col 249 | return row 250 | 251 | else: 252 | col.next = temp 253 | temp.prev.next = col 254 | col.prev = temp.prev 255 | temp.prev = col 256 | return row 257 | prev = temp 258 | temp = temp.next 259 | prev.next = col 260 | col.prev = prev 261 | return row 262 | def insertRowinMatrix(self, newrow:RowNode, indexRow:RowNode): 263 | if(indexRow == self.head): 264 | newrow.next = indexRow 265 | indexRow.prev = newrow 266 | self.head = newrow 267 | else: 268 | newrow.next = indexRow 269 | newrow.prev = indexRow.prev 270 | indexRow.prev.next = newrow 271 | indexRow.prev = newrow 272 | return newrow 273 | def buildSpreadsheet(self, lCells: [Cell]): 274 | """ 275 | Construct the data structure to store nodes. 276 | @param lCells: list of cells to be stored 277 | """ 278 | for cell in lCells: 279 | # Check If Row Node List has set 280 | if (cell.row >= self.c_row): 281 | self.c_row = cell.row + 1 282 | if (cell.col >= self.c_col): 283 | self.c_col = cell.col + 1 284 | col = ColNode(cell.col, cell.val) 285 | row = RowNode(cell.row) 286 | isOK = False 287 | if(self.head == None): 288 | 289 | row = self.insertColinRow(row, col) 290 | self.head = row 291 | isOK = True 292 | else: 293 | temp : RowNode = self.head 294 | prev : RowNode = None 295 | while(temp != None): 296 | if(temp.row_num == cell.row): 297 | temp = self.insertColinRow(temp, col) 298 | isOK = True 299 | break 300 | elif(temp.row_num > cell.row): 301 | temp = self.insertRowinMatrix(row,temp) 302 | 303 | temp = self.insertColinRow(temp, col) 304 | isOK = True 305 | break 306 | prev = temp 307 | temp = temp.next 308 | if(isOK == False): 309 | prev.next = row 310 | row.prev = prev 311 | isOK = True 312 | 313 | 314 | 315 | -------------------------------------------------------------------------------- /spreadsheetFilebased.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from spreadsheet.cell import Cell 3 | from spreadsheet.baseSpreadsheet import BaseSpreadsheet 4 | from spreadsheet.arraySpreadsheet import ArraySpreadsheet 5 | from spreadsheet.linkedlistSpreadsheet import LinkedListSpreadsheet 6 | from spreadsheet.csrSpreadsheet import CSRSpreadsheet 7 | 8 | 9 | # ------------------------------------------------------------------- 10 | # DON'T CHANGE THIS FILE. 11 | # This is the entry point to run the program in file-based mode. 12 | # It uses the data file to initialise the set of words & frequencies. 13 | # It takes a command file as input and output into the output file. 14 | # Refer to usage() for exact format of input expected to the program. 15 | # 16 | # __author__ = 'Jeffrey Chan, original file by Son Hoang Dau' 17 | # __copyright__ = 'Copyright 2023, RMIT University' 18 | # ------------------------------------------------------------------- 19 | 20 | def usage(): 21 | """ 22 | Print help/usage message. 23 | """ 24 | 25 | # On Teaching servers, use 'python3' 26 | # On Windows, you may need to use 'python' instead of 'python3' to get this to work 27 | print('python3 spreadsheetFilebased.py', ' ') 28 | print(' = ') 29 | sys.exit(1) 30 | 31 | 32 | if __name__ == '__main__': 33 | # Fetch the command line arguments 34 | args = sys.argv 35 | 36 | if len(args) != 5: 37 | print('Incorrect number of arguments.') 38 | usage() 39 | 40 | # initialise spreadsheet object 41 | spreadsheet: BaseSpreadsheet = None 42 | if args[1] == 'array': 43 | spreadsheet = ArraySpreadsheet() 44 | elif args[1] == 'linkedlist': 45 | spreadsheet = LinkedListSpreadsheet() 46 | elif args[1] == 'csr': 47 | spreadsheet = CSRSpreadsheet() 48 | else: 49 | print('Incorrect argument value.') 50 | usage() 51 | 52 | # read from data file to populate the initial set of points 53 | dataFilename = args[2] 54 | cellsFromFiles = [] 55 | try: 56 | dataFile = open(dataFilename, 'r') 57 | for line in dataFile: 58 | values = line.split() 59 | currRow = int(values[0]) 60 | currCol = int(values[1]) 61 | currVal = float(values[2]) 62 | currCell = Cell(currRow, currCol, currVal) 63 | # each line contains a cell 64 | cellsFromFiles.append(currCell) 65 | dataFile.close() 66 | # construct the spreadsheet from the read in data 67 | spreadsheet.buildSpreadsheet(cellsFromFiles) 68 | except FileNotFoundError as e: 69 | print("Data file doesn't exist.") 70 | usage() 71 | 72 | # filename of input commands 73 | commandFilename = args[3] 74 | # filename of output 75 | outputFilename = args[4] 76 | 77 | # Parse the commands in command file 78 | try: 79 | commandFile = open(commandFilename, 'r') 80 | outputFile = open(outputFilename, 'w') 81 | 82 | # for each command 83 | for line in commandFile: 84 | commandValues = line.split() 85 | command = commandValues[0] 86 | command = command.upper() 87 | # append row 88 | if command == 'AR': 89 | result = spreadsheet.appendRow() 90 | if result: 91 | outputFile.write("Call to appendRow() returned success.\n") 92 | else: 93 | outputFile.write("Call to appendRow() returned failture.\n") 94 | # append column 95 | elif command == 'AC': 96 | result = spreadsheet.appendCol() 97 | if result: 98 | outputFile.write("Call to appendCol() returned success.\n") 99 | else: 100 | outputFile.write("Call to appendCol() returned failture.\n") 101 | # insert row 102 | elif command == 'IR': 103 | rowIndex = int(commandValues[1]) 104 | result = spreadsheet.insertRow(rowIndex); 105 | if result: 106 | outputFile.write("Call to insertRow(" + str(rowIndex) + ") returned success.\n") 107 | else: 108 | outputFile.write("Call to insertRow(" + str(rowIndex) + ") returned failure.\n") 109 | # insert column 110 | elif command == 'IC': 111 | colIndex = int(commandValues[1]) 112 | result = spreadsheet.insertCol(colIndex); 113 | if result: 114 | outputFile.write("Call to insertCol(" + str(colIndex) + ") returned success.\n") 115 | else: 116 | outputFile.write("Call to insertCol(" + str(colIndex) + ") returned failure.\n") 117 | # update value 118 | elif command == 'U': 119 | rowIndex = int(commandValues[1]) 120 | colIndex = int(commandValues[2]) 121 | value = float(commandValues[3]) 122 | result = spreadsheet.update(rowIndex, colIndex, value); 123 | if result: 124 | outputFile.write("Call to update(" + str(rowIndex) + "," + str(colIndex) + "," + str(value) + ") returned success.\n") 125 | else: 126 | outputFile.write("Call to update(" + str(rowIndex) + "," + str(colIndex) + "," + str(value) + ") returned failure.\n") 127 | # number of rows 128 | elif command == 'R': 129 | result = spreadsheet.rowNum(); 130 | outputFile.write("Number of rows = " + str(result) + "\n") 131 | # number of columns 132 | elif command == 'C': 133 | result = spreadsheet.colNum(); 134 | outputFile.write("Number of columns = " + str(result) + "\n") 135 | # find value 136 | elif command == 'F': 137 | value = float(commandValues[1]) 138 | lCells = spreadsheet.find(value); 139 | outputFile.write("Printing output of find(" + str(value) + "): ") 140 | outputFile.write(" | ".join(["".join(["(", str(cell[0]), ",", str(cell[1]), ")"]) for cell in lCells])) 141 | outputFile.write("\n") 142 | # enumerate all entries that has a value in spreadsheet 143 | elif command == 'E': 144 | lCells = spreadsheet.entries(); 145 | outputFile.write("Printing output of entries(): ") 146 | outputFile.write(" | ".join([cell.__str__() for cell in lCells])) 147 | outputFile.write("\n") 148 | else: 149 | print('Unknown command.') 150 | print(line) 151 | 152 | outputFile.close() 153 | commandFile.close() 154 | except FileNotFoundError as e: 155 | print("Command file doesn't exist.") 156 | usage() 157 | --------------------------------------------------------------------------------