#!/usr/bin/python3 """Find a zip code at the center of n zip codes.""" import sys import math # Zipcode||Latitude||Longitude||State||City||County # 00501||40.817967||-73.045257||NY||HOLTSVILLE||SUFFOLK by_zip = {} by_lat_long = {} # This is pretty much an invariant # latitude_scale = 69.1 # This varies quite a lot; this number is kind of close for SoCal but known to be a bit off. It's really for 40 degrees North (or # South), of the equator, and we're more like 33 degrees. # longitude_scale = 53 # see below for a better calculation - in the final approximate_distance_in_miles method class Point: """A class to hold latitude and longitude pairs, along with zip code, city, stat and country.""" def __init__(self, zip_code, latitude, longitude, state, city, county): """Initialize.""" self.zip_code = zip_code self.latitude = float(latitude) self.longitude = float(longitude) self.state = state self.city = city self.county = county def __str__(self): """Convert to string.""" tuple_ = (self.zip_code, self.latitude, self.longitude, self.state, self.city, self.county) return '%s / lat: %.2f / lon: %.2f / %s / %s / %s' % tuple_ # based on "improved accuracy" at http://www.meridianworlddata.com/distance-calculation.asp def approximate_distance_in_miles(self, other_latitude, other_longitude): """Approximate the distance in miles, from one lat/long to another.""" scale = 69.1 x = scale * (other_latitude - self.latitude) y = scale * (other_longitude - self.longitude) * math.cos(self.latitude / 57.3) return (x ** 2 + y ** 2) ** 0.5 file = open('zipcodes_2006.txt', 'r') for line in file: fields = line.rstrip().split('|') zip_code = fields[0] latitude = fields[2] longitude = fields[4] state = fields[6] city = fields[8] county = fields[10] p = Point(zip_code, latitude, longitude, state, city, county) by_zip[zip_code] = p by_lat_long[(latitude, longitude)] = p file.close() num_zips = 0 total_latitude = 0 total_longitude = 0 for zip_code in sys.argv[1:]: num_zips += 1 total_latitude += by_zip[zip_code].latitude total_longitude += by_zip[zip_code].longitude print('got', by_zip[zip_code]) average_latitude = total_latitude / num_zips average_longitude = total_longitude / num_zips def closest_zip(by_zip, lat, long): """Find the closest zip code.""" best_zip = -1 best_distance = None for zip_code, point in by_zip.items(): current_distance = point.approximate_distance_in_miles(lat, long) if best_distance is None or best_distance > current_distance: best_distance = current_distance best_zip = zip_code return best_zip best_zip = closest_zip(by_zip, average_latitude, average_longitude) print('result is', by_zip[best_zip]) print() for zip_code in sys.argv[1:]: tuple_ = ( zip_code, by_zip[best_zip].approximate_distance_in_miles(by_zip[zip_code].latitude, by_zip[zip_code].longitude), best_zip, ) print('%s: about %.1f miles from %s as the crow flies' % tuple_)