97 lines
3.2 KiB
Python
97 lines
3.2 KiB
Python
# 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]
|