-1

Let's say there is a JSON file with cities and their coordinates.

  {
    "country": "AT",
    "name": "Fladnitz im Raabtal",
    "lat": "46.99167",
    "lng": "15.78528"
  }

I am getting users Longitude and Latitude for example Latitude 46.98 and Longitude 15.77. Now I would like to search for City and Country in JSON (in this case "name" and "country"). However values does not match exactly. How I can get closest possible Latitude and Longitude values from JSON?

Here is Location class

  public class Location
  {
    public string Country { get; set; }
    [JsonPropertyName("name")]
    public string City { get; set; }
    [JsonPropertyName("lat")]
    public double Latitude { get; set; }
    [JsonPropertyName("lng")]
    public double Longitude { get; set; }
  }

Here is LINQ for filtering but I am not getting how to perform "get closest number operation in here"?

      City.Text = this.Locations.Where(w => w.Latitude == lat && w.Longitude == lng)
                                .Select(s => s.City)
                                .DefaultIfEmpty("Unknown")
                                .First()
                                .ToString();
10101
  • 2,232
  • 3
  • 26
  • 66
  • 1
    All you need to do is come up with an algorithm to find the closest. That's really not that hard if you think about it. You could loop through the existing items, calculate their distance from the provided point using a distance formula and then pick the one with the shortest distance. Give it a try. – mason Oct 05 '21 at 22:20
  • 1
    Try this (.NET Standard compatible): https://www.nuget.org/packages/GeoCoordinate.NetCore/ - or (old .NET Framework only): https://learn.microsoft.com/en-us/dotnet/api/system.device.location.geocoordinate – Peter B Oct 05 '21 at 22:24
  • @mason GeoCoordinates don't use distance formula (unless the Earth is flat) – OneCricketeer Oct 05 '21 at 22:26
  • @OneCricketeer Fair enough. It may not make a difference though, for example if this is a school exercise. – mason Oct 05 '21 at 22:29
  • Since it is not clear where you stuck I pick two different duplicates based on my understanding of what you don't know - compute distance and min/max by computed property. Please [edit] question to clarify if you are looking for something else altogether. – Alexei Levenkov Oct 05 '21 at 22:31
  • 2
    You have two sets of numbers (Latitude and Longitude) to deal with. Not one set. Therefore simply finding the closest number won't work. You have to calculate distance. And you may or may not need to account for the curvature of the Earth. – mason Oct 05 '21 at 22:33
  • 1
    @hatman you know deep inside your heart that you need distance (or any other [norm](https://en.wikipedia.org/wiki/Norm_(mathematics))) as there is no way to find "closest" to two separate values... But anyway, good to know that my second duplicat is exactly what you were looking for. – Alexei Levenkov Oct 05 '21 at 22:35

1 Answers1

0

There are 2 methods to finding the location by an unexact coordinate. The first solution is to use a coordinate variance, the second is to use distance. Each have their own benefits so choose wisely.

Solution 1: Since the coordinates are not exactly matching we must come up with an allowed variance. For this example i will use 0.001 variance for Lat and Long.

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
                    
public class Program {
    public class Location {
    public string Country { get; set; }
    public string City { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public Location(string Country_, string City_, double Latitude_, double Longitude_){
        this.Country = Country_;
        this.City = City_;
        this.Latitude = Latitude_;
        this.Longitude = Longitude_;
    }
  }
    
    public static void Main() {
        List<Location> locations = new List<Location>();
        locations.Add(new Location("USA", "Daytona Beach", 29.2108, 81.0228));
        locations.Add(new Location("USA", "Miami", 25.7617,80.1918));
        locations.Add(new Location("USA", "Jacksonville", 30.3322,81.6557));
        
        double variance = 0.001;
        
        double searchLat = 29.21; //unexact lat of daytona beach
        Console.WriteLine(
            locations.Where(w => w.Latitude >= searchLat - variance && w.Latitude <= searchLat + variance)
            .Select(s => s.City)
            .DefaultIfEmpty("Unknown")
            .First()
            .ToString()
        );
        
    }
}

Solution 2: I don't really recommend this because of how process heavy this can be but just incase distance is actually important.. You will need to iterate over each of the location coordinates with your search coordinate and select the smallest distance. Coordinate method ripped from here: Calculating Distance between two Latitude and Longitude GeoCoordinates

using System;
using System.Collections.Generic;
using System.Linq;
public class Program {
    public class Location {
        public string Country { get; set; }
        public string City { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public Location(string Country_, string City_, double Latitude_, double Longitude_) {
            this.Country = Country_;
            this.City = City_;
            this.Latitude = Latitude_;
            this.Longitude = Longitude_;
        }
    }

    static void Main(string[] args) {
        List<Location> locations = new List<Location>();
        locations.Add(new Location("USA", "Daytona Beach", 29.2108, 81.0228));
        locations.Add(new Location("USA", "Miami", 25.7617, 80.1918));
        locations.Add(new Location("USA", "Jacksonville", 30.3322, 81.6557));

        double searchLat = 30;
        double searchLong = 81;

        Dictionary<double, List<Location>> distances = new Dictionary<double, List<Location>>();

        locations.ForEach(location => {
            double distance = Program.GetDistance(location.Latitude, location.Longitude, searchLat, searchLong);
            if(distances.ContainsKey(distance)){
                distances[distance].Add(location);
            }else{
                distances.Add(distance, new List<Location>() { location });
            }
        });

        double closestDistanceFromSearch = distances.Keys.OrderBy(k => k).First();

        Console.WriteLine(
            distances[distances.Keys.OrderBy(k => k).First()].First().City
        );

    }
    public static double GetDistance(double latitude, double longitude, double otherLatitude, double otherLongitude) {
        var d1 = latitude * (Math.PI / 180.0);
        var num1 = longitude * (Math.PI / 180.0);
        var d2 = otherLatitude * (Math.PI / 180.0);
        var num2 = otherLongitude * (Math.PI / 180.0) - num1;
        var d3 = Math.Pow(Math.Sin((d2 - d1) / 2.0), 2.0) + Math.Cos(d1) * Math.Cos(d2) * Math.Pow(Math.Sin(num2 / 2.0), 2.0);

        return 6376500.0 * (2.0 * Math.Atan2(Math.Sqrt(d3), Math.Sqrt(1.0 - d3)));
    }
}
THE AMAZING
  • 1,496
  • 2
  • 16
  • 38