# Student ID: 012498637 # Student Name: Zakaria Benmoulay # Course: C950 - Data Structures and Algorithms II import csv from package import Package from hash_table import ChainingHashTable def load_packages(filepath): # Let's read packages.csv and load all package records into a hash table. table = ChainingHashTable() with open(filepath, newline="", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: # Build a Package object from each CSV row pkg = Package( package_id=row["PackageID"], address=row["Address"], city=row["City"], state=row["State"], zip_code=row["Zip"], deadline=row["Deadline"], weight=row["Weight"], notes=row["Notes"], ) # Insert into the hash table using package ID as the key table.insert(pkg.package_id, pkg) # Let's return the hash table keyed by package ID return table def load_distances(filepath): # Let's read distances.csv and build a symmetric 2-D distance matrix. address_list = [] raw_rows = [] with open(filepath, newline="", encoding="utf-8") as f: reader = csv.reader(f) # First row contains the column headers (location name + address) header = next(reader) # Extract the short street address from each header cell. # Header cells may contain a full location name followed by the # street address separated by whitespace; we take the last part. for cell in header[1:]: # skip the first "Address" label column parts = [p.strip() for p in cell.replace("\n", " ").split(" ") if p.strip()] address_list.append(parts[-1] if parts else cell.strip()) # Read the remaining rows — each row is one location's distances for row in reader: raw_rows.append(row[1:]) # drop the first column (location label) m = len(address_list) # Create an m×m matrix filled with 0.0 matrix = [[0.0] * m for _ in range(m)] # Fill in the matrix - the CSV only has the lower triangle for i, row in enumerate(raw_rows): for j, cell in enumerate(row): if cell.strip() == "" or cell is None: continue dist = float(cell) matrix[i][j] = dist matrix[j][i] = dist return address_list, matrix def get_distance(address_list, distance_matrix, addr_a, addr_b): # Let's find the index of an address using flexible matching. def find_index(addr): addr_clean = addr.strip().lower() # Pass 1: exact match (fastest, covers most cases) for i, a in enumerate(address_list): if a.strip().lower() == addr_clean: return i # Pass 2: substring match (handles minor formatting differences) for i, a in enumerate(address_list): if addr_clean in a.strip().lower() or a.strip().lower() in addr_clean: return i # Raise an error if the address cannot be found. raise ValueError(f"Address not found in distance table: '{addr}'") i = find_index(addr_a) j = find_index(addr_b) return distance_matrix[i][j]