CMU Coding Bootcamp
at main 7.8 kB view raw
1possibleData = str | float | None 2 3 4class 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 51class 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 100def 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 107def 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 158def 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 250def main(): 251 testLevel1() 252 testLevel2() 253 254 255main()