package zip import ( _ "embed" "local/truckstop/logtr" "math" "strconv" "strings" ) //go:embed testdata/simplemaps_uszips_basicv1.79/uszips.csv var csv string type Zip struct { Lat float64 Lng float64 City string State string } var zips map[string]Zip func init() { zips = map[string]Zip{} trim := func(s string) string { return strings.Trim(s, `"`) } logtr.Infof("%d", len(csv)) for _, line := range strings.Split(csv, "\n")[1:] { strs := strings.Split(line, ",") if len(strs) < 5 { continue } zip := trim(strs[0]) lat, _ := strconv.ParseFloat(trim(strs[1]), 32) lng, _ := strconv.ParseFloat(trim(strs[2]), 32) city := trim(strs[3]) state := trim(strs[4]) zips[zip] = Zip{ Lat: lat, Lng: lng, City: city, State: state, } logtr.Infof("%+v", zips[zip]) } logtr.Infof("%+v to %+v = %v", Get("27006"), Get("84059"), Get("27006").MilesTo(Get("84059"))) } func (zip Zip) MilesTo(other Zip) int { // c**2 = a**2 + b**2 // 69.2 mi per lat // 60.0 mi per lng return int(math.Sqrt( math.Pow(69.2*(math.Abs(zip.Lat)-math.Abs(other.Lat)), 2) + math.Pow(60.0*(math.Abs(zip.Lng)-math.Abs(other.Lng)), 2), )) } func Get(zip string) Zip { if z, ok := zips[zip]; ok { return z } zipAsI, err := strconv.Atoi(strings.Split(zip, "-")[0]) if err != nil { return Zip{} } for i := 0; i < 5; i++ { j := i - 2 if z2, ok := zips[strconv.Itoa(zipAsI+j)]; ok { return z2 } } return Zip{} }