Skip to content

Commit

Permalink
added DistanceInKmToZipCode, DistanceInMilToZipCode, GetZipcodesWithi…
Browse files Browse the repository at this point in the history
…nKmRadius and GetZipcodesWithinMlRadius methods
  • Loading branch information
fegoa89 committed Apr 15, 2019
1 parent 05f0635 commit 8da45b6
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 5 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,31 @@ Returns the line of sight distance between two zipcodes in miles:
```golang
location, err := zipcodesDataset.DistanceInMiles("01945", "03058") // 30.98
```

### DistanceInKmToZipCode
Calculates the distance between a zipcode and a give lat/lon in Kilometers:

```golang
location, err := zipcodesDataset.DistanceInKmToZipCode("01945", 51.4267, 13.9333) // 1.11
```

### DistanceInMilToZipCode
Calculates the distance between a zipcode and a give lat/lon in Miles:

```golang
location, err := zipcodesDataset.DistanceInMilToZipCode("01945", 51.4267, 13.9333) // 0.69
```

### GetZipcodesWithinKmRadius
Returns a list of zipcodes within the radius of this zipcode in Kilometers:

```golang
location, err := zipcodesDataset.GetZipcodesWithinKmRadius("01945", 50) // ["03058"]
```

### GetZipcodesWithinMlRadius
Returns a list of zipcodes within the radius of this zipcode in Miles:

```golang
location, err := zipcodesDataset.GetZipcodesWithinMlRadius("01945", 50) // ["03058"]
```
61 changes: 59 additions & 2 deletions zipcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

const (
earthRaidusKm = 6371
earthRadiusKm = 6371
earthRadiusMi = 3958
)

Expand Down Expand Up @@ -53,7 +53,7 @@ func (zc *Zipcodes) Lookup(zipCode string) (*ZipCodeLocation, error) {

// DistanceInKm returns the line of sight distance between two zipcodes in Kilometers
func (zc *Zipcodes) DistanceInKm(zipCodeA string, zipCodeB string) (float64, error) {
return zc.CalculateDistance(zipCodeA, zipCodeB, earthRaidusKm)
return zc.CalculateDistance(zipCodeA, zipCodeB, earthRadiusKm)
}

// DistanceInMiles returns the line of sight distance between two zipcodes in Miles
Expand All @@ -76,6 +76,63 @@ func (zc *Zipcodes) CalculateDistance(zipCodeA string, zipCodeB string, radius f
return DistanceBetweenPoints(locationA.Lat, locationA.Lon, locationB.Lat, locationB.Lon, radius), nil
}

// DistanceInKmToZipcode calculates the distance between a zipcode and a give lat/lon in Kilometers
func (zc *Zipcodes) DistanceInKmToZipCode(zipCode string, latitude, longitude float64) (float64, error) {
location, errLoc := zc.Lookup(zipCode)
if errLoc != nil {
return 0, errLoc
}

return DistanceBetweenPoints(location.Lat, location.Lon, latitude, longitude, earthRadiusKm), nil
}

// DistanceInMilToZipcode calculates the distance between a zipcode and a give lat/lon in Miles
func (zc *Zipcodes) DistanceInMilToZipCode(zipCode string, latitude, longitude float64) (float64, error) {
location, errLoc := zc.Lookup(zipCode)
if errLoc != nil {
return 0, errLoc
}

return DistanceBetweenPoints(location.Lat, location.Lon, latitude, longitude, earthRadiusMi), nil
}

// GetZipcodesWithinKmRadius get all zipcodes within the radius of this zipcode
func (zc *Zipcodes) GetZipcodesWithinKmRadius(zipCode string, radius float64) ([]string, error) {
zipcodeList := []string{}
location, errLoc := zc.Lookup(zipCode)
if errLoc != nil {
return zipcodeList, errLoc
}

return zc.FindZipcodesWithinRadius(location, radius, earthRadiusKm), nil
}

// GetZipcodesWithinMlRadius get all zipcodes within the radius of this zipcode
func (zc *Zipcodes) GetZipcodesWithinMlRadius(zipCode string, radius float64) ([]string, error) {
zipcodeList := []string{}
location, errLoc := zc.Lookup(zipCode)
if errLoc != nil {
return zipcodeList, errLoc
}

return zc.FindZipcodesWithinRadius(location, radius, earthRadiusMi), nil
}

// FindZipcodesWithinRadius finds zipcodes within a given radius
func (zc *Zipcodes) FindZipcodesWithinRadius(location *ZipCodeLocation, maxRadius float64, earthRadius float64) []string {
zipcodeList := []string{}
for _, elm := range zc.DatasetList {
if elm.ZipCode != location.ZipCode {
distance := DistanceBetweenPoints(location.Lat, location.Lon, elm.Lat, elm.Lon, earthRadius)
if distance < maxRadius {
zipcodeList = append(zipcodeList, elm.ZipCode)
}
}
}

return zipcodeList
}

func hsin(t float64) float64 {
return math.Pow(math.Sin(t/2), 2)
}
Expand Down
195 changes: 192 additions & 3 deletions zipcodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func TestDistanceBetweenPoints(t *testing.T) {
}

for _, c := range cases {
kms := DistanceBetweenPoints(c.coordsA[0], c.coordsA[1], c.coordsB[0], c.coordsB[1], earthRaidusKm)
kms := DistanceBetweenPoints(c.coordsA[0], c.coordsA[1], c.coordsB[0], c.coordsB[1], earthRadiusKm)
if kms != c.ExpectedKM {
t.Errorf("Distance does not match. Expected %v, got %v", c.ExpectedKM, kms)
}
Expand Down Expand Up @@ -144,7 +144,7 @@ func TestCalculateDistance(t *testing.T) {
}

for _, c := range cases {
kms, err := zipcodesDataset.CalculateDistance(c.ZipCodeA, c.ZipCodeB, earthRaidusKm)
kms, err := zipcodesDataset.CalculateDistance(c.ZipCodeA, c.ZipCodeB, earthRadiusKm)
if err != nil {
t.Errorf("Unexpected error while looking for zipcode %s", err)
}
Expand Down Expand Up @@ -177,7 +177,7 @@ func TestCalculateDistance(t *testing.T) {
}

for _, c := range fail {
_, err := zcDataset.CalculateDistance(c.ZipCodeA, c.ZipCodeB, earthRaidusKm)
_, err := zcDataset.CalculateDistance(c.ZipCodeA, c.ZipCodeB, earthRadiusKm)
if err.Error() != c.ExpectedErr {
t.Errorf("Unexpected error. Got %s, want %s", err, c.ExpectedErr)
}
Expand Down Expand Up @@ -261,3 +261,192 @@ func TestDistanceInMiles(t *testing.T) {
}
}
}

func TestDistanceInKmToZipCode(t *testing.T) {
cases := []struct {
ZipCode string
Latitude float64
Longitude float64
ExpectedResponse float64
}{
{
"01945",
51.4267,
13.9333,
1.11,
},
{
"01945",
51.4067,
13.9333,
1.11,
},
}

zipcodesDataset, err := New("datasets/valid_dataset.txt")
if err != nil {
t.Errorf("Unexpected error while initializing struct %v", err)
}

for _, c := range cases {
kms, err := zipcodesDataset.DistanceInKmToZipCode(c.ZipCode, c.Latitude, c.Longitude)

if err != nil {
t.Errorf("Unexpected error while looking for zipcode %s", err)
}

if kms != c.ExpectedResponse {
t.Errorf("Expected distance in kilometers to zipcode does not match. Expected %v, got %v", c.ExpectedResponse, kms)
}
}
}

func TestDistanceInMilToZipCode(t *testing.T) {
cases := []struct {
ZipCode string
Latitude float64
Longitude float64
ExpectedResponse float64
}{
{
"01945",
51.4267,
13.9333,
0.69,
},
{
"01945",
51.4067,
13.9333,
0.69,
},
}

zipcodesDataset, err := New("datasets/valid_dataset.txt")
if err != nil {
t.Errorf("Unexpected error while initializing struct %v", err)
}

for _, c := range cases {
miles, err := zipcodesDataset.DistanceInMilToZipCode(c.ZipCode, c.Latitude, c.Longitude)

if err != nil {
t.Errorf("Unexpected error while looking for zipcode %s", err)
}

if miles != c.ExpectedResponse {
t.Errorf("Expected distance in miles to zipcode does not match. Expected %v, got %v", c.ExpectedResponse, miles)
}
}
}

func TestGetZipcodesWithinKmRadius(t *testing.T) {
cases := []struct {
ZipCode string
Radius float64
ExpectedResponse []string
}{
{
"01945",
50.0,
[]string{"03058"},
},
{
"01945",
100.0,
[]string{"03058"},
},
}
zipcodesDataset, err := New("datasets/valid_dataset.txt")
if err != nil {
t.Errorf("Unexpected error while initializing struct %v", err)
}
for _, c := range cases {
zcList, err := zipcodesDataset.GetZipcodesWithinKmRadius(c.ZipCode, c.Radius)
if err != nil {
t.Errorf("Unexpected error while looking for zipcode %s", err)
}

if reflect.DeepEqual(zcList, c.ExpectedResponse) != true {
t.Errorf("Unxpected zipcode list returned.")
}
}
}

func TestGetZipcodesWithinMlRadius(t *testing.T) {
cases := []struct {
ZipCode string
Radius float64
ExpectedResponse []string
}{
{
"01945",
50.0,
[]string{"03058"},
},
{
"01945",
100.0,
[]string{"03058"},
},
}
zipcodesDataset, err := New("datasets/valid_dataset.txt")
if err != nil {
t.Errorf("Unexpected error while initializing struct %v", err)
}
for _, c := range cases {
zcList, err := zipcodesDataset.GetZipcodesWithinMlRadius(c.ZipCode, c.Radius)
if err != nil {
t.Errorf("Unexpected error while looking for zipcode %s", err)
}

if reflect.DeepEqual(zcList, c.ExpectedResponse) != true {
t.Errorf("Unxpected zipcode list returned.")
}
}
}

func TestFindZipcodesWithinRadius(t *testing.T) {
cases := []struct {
Location *ZipCodeLocation
MaxRadius float64
EarthRadius float64
ExpectedList []string
}{
{
&ZipCodeLocation{
ZipCode: "01945",
PlaceName: "Guteborn",
AdminName: "Brandenburg",
Lat: 51.4167,
Lon: 13.9333,
},
50,
earthRadiusKm,
[]string{"03058"},
},
{
&ZipCodeLocation{
ZipCode: "01945",
PlaceName: "Guteborn",
AdminName: "Brandenburg",
Lat: 51.4167,
Lon: 13.9333,
},
50,
earthRadiusKm,
[]string{"03058"},
},
}
zipcodesDataset, err := New("datasets/valid_dataset.txt")
if err != nil {
t.Errorf("Unexpected error while initializing struct %v", err)
}
for _, c := range cases {
list := zipcodesDataset.FindZipcodesWithinRadius(c.Location, c.MaxRadius, c.EarthRadius)

if reflect.DeepEqual(list, c.ExpectedList) != true {
t.Errorf("FindZipcodesWithinRadius returned an unexpected zipcode list.")
}
}
}

0 comments on commit 8da45b6

Please sign in to comment.