CMU Coding Bootcamp

feat: oct 10 tables

thecoded.prof 8edd123b e6c70271

verified
Changed files
+255
python
oct10
Tables
+255
python/oct10/Tables/main.py
··· 1 + possibleData = str | float | None 2 + 3 + 4 + class DataList: 5 + data: list[possibleData] 6 + 7 + def __init__(self, L: list[possibleData]) -> None: 8 + self.data = L 9 + 10 + def __getitem__(self, index: int) -> possibleData: 11 + return self.data[index] 12 + 13 + def __len__(self) -> int: 14 + return len(self.data) 15 + 16 + def numericValues(self) -> list[float | int]: 17 + items = [item for item in self.data if isinstance(item, float | int)] 18 + return items 19 + 20 + def min(self) -> float: 21 + return sorted(self.numericValues())[0] 22 + 23 + def average(self) -> float: 24 + nvs = self.numericValues() 25 + return sum(nvs) / len(nvs) 26 + 27 + def median(self) -> float | None: 28 + nvs = self.numericValues() 29 + if len(nvs) == 0: 30 + return None 31 + snvs = list(sorted(nvs)) 32 + middle = len(nvs) // 2 33 + if len(nvs) % 2 == 1: 34 + return snvs[middle] 35 + else: 36 + sl = snvs[middle - 1 : middle + 1] 37 + return sum(sl) / 2 38 + 39 + def max(self) -> float: 40 + return list(reversed(sorted(self.numericValues())))[0] 41 + 42 + def range(self) -> tuple[float, float]: 43 + return (self.min(), self.max()) 44 + 45 + @property 46 + def values(self) -> list[float | int | None]: 47 + values = [item for item in self.data if (isinstance(item, float | int | None))] 48 + return values 49 + 50 + 51 + class Table: 52 + data: list[DataList] 53 + 54 + def __init__(self, data: list[list[possibleData]]) -> None: 55 + self.data = [] 56 + m, n = len(data), len(data[0]) 57 + result: list[list[possibleData]] = [] 58 + for col in range(n): 59 + result.append([]) 60 + for row in range(m): 61 + result[col].append(data[row][col]) 62 + for row in result: 63 + dl = DataList(row) 64 + self.data.append(dl) 65 + 66 + def getHeaders(self) -> list[str]: 67 + return [str(r[0]) for r in self.data] 68 + 69 + def _getColInt(self, index: int) -> DataList: 70 + if index >= len(self.data): 71 + raise IndexError(f"Col {index} is out of range") 72 + return self.data[index] 73 + 74 + def _getColStr(self, index: str) -> DataList: 75 + hi = self.getHeaderIndex(index) 76 + return self._getColInt(hi) 77 + 78 + def getCol(self, index: int | str) -> DataList: 79 + if isinstance(index, int): 80 + return self._getColInt(index) 81 + else: 82 + return self._getColStr(index) 83 + 84 + def getRow(self, index: int) -> list[possibleData]: 85 + if index + 1 >= len(self.data[0]): 86 + raise IndexError(f"Row {index} is out of range") 87 + else: 88 + row = [c[index + 1] for c in self.data] 89 + return row 90 + 91 + def getHeaderIndex(self, header: str) -> int: 92 + headers = [c[0] for c in self.data] 93 + for i, h in enumerate(headers): 94 + if h == header: 95 + return i 96 + else: 97 + raise KeyError(f"No such header: {header}") 98 + 99 + 100 + def almostEqual(x: float | None, y: float | None) -> bool: 101 + if x == None or y == None: 102 + return False 103 + epsilon = 10**-9 104 + return abs(x - y) < epsilon 105 + 106 + 107 + def testLevel1(): 108 + print("Testing Level 1 (Core) material...", end="") 109 + # First test DataList: 110 + dl = DataList([5, 2, None, 1.1, "yikes", 3.9]) 111 + assert type(dl) == DataList 112 + assert dl.numericValues() == [5, 2, 1.1, 3.9] 113 + assert dl.min() == 1.1 114 + assert dl.max() == 5 115 + 116 + # Now test Table and TableRow 117 + weatherData: list[list[possibleData]] = [ 118 + ["Date", "Low", "High"], 119 + ["1-Aug", 63, 81], 120 + ["2-Aug", 67, 85], 121 + ["3-Aug", 64, 86], 122 + ["4-Aug", 61, None], 123 + ["5-Aug", None, None], 124 + ["6-Aug", 59, 71], 125 + ["7-Aug", 63, 77], 126 + ["8-Aug", 68, 88], 127 + ["9-Aug", 75, 91], 128 + ["10-Aug", 74, 93], 129 + ] 130 + table = Table(weatherData) 131 + assert table.getHeaders() == ["Date", "Low", "High"] 132 + 133 + lows = table.getCol(1) 134 + assert type(lows) == DataList 135 + assert lows.values == [63, 67, 64, 61, None, 59, 63, 68, 75, 74] 136 + assert lows.numericValues() == [63, 67, 64, 61, 59, 63, 68, 75, 74] 137 + assert lows.min() == 59 138 + assert lows.max() == 75 139 + 140 + highs = table.getCol(2) 141 + assert type(highs) == DataList 142 + assert highs.values == [81, 85, 86, None, None, 71, 77, 88, 91, 93] 143 + assert highs.numericValues() == [81, 85, 86, 71, 77, 88, 91, 93] 144 + assert highs.min() == 71 145 + assert highs.max() == 93 146 + 147 + # We will try to get col 3, but that is out of range, 148 + # so it will raise a custom exception. 149 + error = None 150 + try: 151 + col = table.getCol(3) 152 + except Exception as e: 153 + error = str(e) 154 + assert error == "Col 3 is out of range" 155 + print("Passed!") 156 + 157 + 158 + def testLevel2(): 159 + print("Testing Level 2+ (Not Core) material...", end="") 160 + # First test DataList: 161 + dl = DataList([5, 2, None, 1.1, "yikes", 3.9]) 162 + assert dl.range() == (1.1, 5) 163 + assert almostEqual(dl.average(), 3) 164 + 165 + # Now test Table and TableRow 166 + weatherData: list[list[possibleData]] = [ 167 + ["Date", "Low", "High"], 168 + ["1-Aug", 63, 81], 169 + ["2-Aug", 67, 85], 170 + ["3-Aug", 64, 86], 171 + ["4-Aug", 61, None], 172 + ["5-Aug", None, None], 173 + ["6-Aug", 59, 71], 174 + ["7-Aug", 63, 77], 175 + ["8-Aug", 68, 88], 176 + ["9-Aug", 75, 91], 177 + ["10-Aug", 74, 93], 178 + ] 179 + table = Table(weatherData) 180 + assert table.getHeaders() == ["Date", "Low", "High"] 181 + 182 + assert table.getRow(0) == ["1-Aug", 63, 81] 183 + assert table.getRow(9) == ["10-Aug", 74, 93] 184 + 185 + # We will try to get row 10, but that is out of range, 186 + # so it will raise a custom exception. 187 + error = None 188 + try: 189 + row = table.getRow(10) 190 + except Exception as e: 191 + error = str(e) 192 + assert error == "Row 10 is out of range" 193 + 194 + assert table.getHeaderIndex("Date") == 0 195 + assert table.getHeaderIndex("Low") == 1 196 + assert table.getHeaderIndex("High") == 2 197 + 198 + # We will try to find the header index of 'Missing', but 199 + # there is no such header, so it will raise a custom exception. 200 + error = None 201 + try: 202 + i = table.getHeaderIndex("Missing") 203 + except Exception as e: 204 + error = str(e) 205 + # assert(error == 'No such header: Missing') 206 + 207 + lows = table.getCol("Low") # hint: use getHeaderIndex! 208 + assert type(lows) == DataList 209 + assert lows.values == [63, 67, 64, 61, None, 59, 63, 68, 75, 74] 210 + assert lows.range() == (59, 75) 211 + assert almostEqual(lows.average(), 66) 212 + 213 + highs = table.getCol("High") 214 + assert type(highs) == DataList 215 + assert highs.values == [81, 85, 86, None, None, 71, 77, 88, 91, 93] 216 + assert highs.range() == (71, 93) 217 + assert almostEqual(highs.average(), 84) 218 + 219 + # And for one last challenge: 220 + # We define the MEDIAN of a list like so: 221 + # * If the list has odd length, then the median is 222 + # the middle value of the sorted list. 223 + # * If the list has even length, then the median is 224 + # the average of the two middle values of the sorted list. 225 + # For example: 226 + # median([11, 19, 7, 14, 3]) 227 + # * This list has length 5, which is odd, so the median is the 228 + # middle value of the sorted list, [3, 7, 11, 14, 19], 229 + # which is 11. 230 + # median([11, 19, 7, 14]) 231 + # * This list has length 4, which is even, so the median is the 232 + # average of the two middle value of the sorted list, 233 + # [7, 11, 14, 19], which is (11 + 14)/2 = 25/2 = 12.5. 234 + # 235 + # With this in mind, pass these additional tests; 236 + dl = DataList([11, 19, 7, 14, 3]) 237 + assert almostEqual(dl.median(), 11) 238 + 239 + dl = DataList([11, 19, 7, 14]) 240 + assert almostEqual(dl.median(), 12.5) 241 + 242 + dl = DataList([]) 243 + assert dl.median() == None # No values, so no median 244 + 245 + assert almostEqual(lows.median(), 64) 246 + assert almostEqual(highs.median(), 85.5) 247 + print("Passed!") 248 + 249 + 250 + def main(): 251 + testLevel1() 252 + testLevel2() 253 + 254 + 255 + main()