0

I have a hash(city: [coordinates]) like this:

cities = {
  l1:  [41.91372380139719,-87.72308349609375], 
  l2:  [42.092312110873536,-87.79449462890625],
  l3:  [42.08008203350686,-87.73406982421875],
  l4:  [41.86976539904969,-87.68325805664062],
  l5:  [41.8861255478388,-87.63381958007812],
  l6:  [41.8891926094646,-87.60635375976562],
  l7:  [41.91678953772886,-87.63107299804688],
  l8:  [41.92496411465408,-87.68051147460938],
  l9:  [41.87283324596932,-87.61734008789062],
  l10: [41.84828634806966,-87.61184692382812],
  l11: [41.86772008597142,-87.63931274414062],
  l12: [41.88510316124205,-87.60498046875],
  l13: [41.84930932360913,-87.62420654296875]
}

Then I am calculating the distance between the first location and the rest of the location like written below and then I put those distances into an array called temp:

temp = []

def distance loc1, loc2
  rad_per_deg = Math::PI/180  # PI / 180
  rkm = 6371                  # Earth radius in kilometers
  rm = rkm * 1000             # Radius in meters

  dlat_rad = (loc2[0]-loc1[0]) * rad_per_deg  # Delta, converted to rad
  dlon_rad = (loc2[1]-loc1[1]) * rad_per_deg

  lat1_rad, lon1_rad = loc1.map {|i| i * rad_per_deg }
  lat2_rad, lon2_rad = loc2.map {|i| i * rad_per_deg }

  a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2
  c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a))

  rm * c # Delta in meters
end

cityarr = cities.to_a

for i in 1..(cityarr.length-1) do
  temp.push (distance [cityarr[0][1][0], cityarr[0][1][1]],[cityarr[i][1][0], cityarr[i][1][1]])
end

puts temp

This code works and I get an array of the distances. My end goal is to output the closest location to the first location("l1").

For example: "L7 is the closest location to L1". Since the elements in the temp array has no association to the keys in the cities hash, I'm not sure how to do this. I can just use puts temp.min to get the smallest distance, but that doesn't output the name of the location.

Is there a way to do it?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Dinukaperera
  • 97
  • 1
  • 10

1 Answers1

1
for i in 1..(cityarr.length-1) do
  temp.push([cityarr[i][0], distance([cityarr[0][1][0], cityarr[0][1][1]],
                                     [cityarr[i][1][0], cityarr[i][1][1]])])
end

temp.min_by { |dist| dist[1] }

That gives you the closest point with the distance. Guess one can find better ways to do that. I'm sure somebody would love to enlighten us with alternatives.

infiniteRefactor
  • 1,940
  • 15
  • 22
  • Thank you so much. Works like a charm. – Dinukaperera Apr 22 '17 at 00:39
  • 1
    You're welcome. Please accept the answer if it answered your question.This way you can both indicate that your question does not necessarily need any more attention and the answer exactly matches your problem. – infiniteRefactor Apr 22 '17 at 00:47
  • Thank you for letting me know about "accepting" the answer. I didn't know about it until you mentioned it. – Dinukaperera Apr 22 '17 at 01:57
  • `for` loops are generally discouraged in Ruby and you should make a point of this. There are other more idiomatic ways. – Sagar Pandya Apr 22 '17 at 02:10
  • @Dinukaperera it's important to accept answers on Stack Overflow but there is no rush in doing so. Take your time and wait and see what other answers are posted. – Sagar Pandya Apr 22 '17 at 02:12
  • @Dinukaperera you can re-accept a different answer if you find it more fitting, or more informative. – infiniteRefactor Apr 22 '17 at 02:13
  • @sagarpandya82 can I please know how you would go about it without a for loop? – Dinukaperera Apr 22 '17 at 02:47
  • I would consider using `cities[:l1]` instead of `cities.first[1]` perhaps. And evolving your final answer I would drop `drop` so you don't end up converting to an array and end up with something like: `cities.min_by(2) { |_,v| distance(cities[:L1], v) }.max` – Sagar Pandya Apr 22 '17 at 05:22
  • I have upvoted your answer once you made the edit and offered suggestions to improve your answer. Which part is offensive? If my logic or understanding is incorrect, I would love to be corrected. – Sagar Pandya Apr 22 '17 at 05:28